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 
17 package com.android.settings;
18 
19 import android.app.AlertDialog;
20 import android.content.Context;
21 import android.content.DialogInterface;
22 import android.os.Bundle;
23 import android.support.v14.preference.ListPreferenceDialogFragment;
24 import android.support.v7.preference.PreferenceViewHolder;
25 import android.util.AttributeSet;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.AdapterView;
29 import android.widget.ArrayAdapter;
30 import android.widget.CheckedTextView;
31 import android.widget.ImageView;
32 import android.widget.ListAdapter;
33 import android.widget.ListView;
34 
35 import com.android.settingslib.RestrictedLockUtils;
36 import com.android.settingslib.RestrictedPreferenceHelper;
37 
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
42 
43 public class RestrictedListPreference extends CustomListPreference {
44     private final RestrictedPreferenceHelper mHelper;
45     private final List<RestrictedItem> mRestrictedItems = new ArrayList<>();
46 
RestrictedListPreference(Context context, AttributeSet attrs)47     public RestrictedListPreference(Context context, AttributeSet attrs) {
48         super(context, attrs);
49         setWidgetLayoutResource(R.layout.restricted_icon);
50         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
51     }
52 
RestrictedListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)53     public RestrictedListPreference(Context context, AttributeSet attrs,
54             int defStyleAttr, int defStyleRes) {
55         super(context, attrs, defStyleAttr, defStyleRes);
56         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
57     }
58 
59     @Override
onBindViewHolder(PreferenceViewHolder holder)60     public void onBindViewHolder(PreferenceViewHolder holder) {
61         super.onBindViewHolder(holder);
62         mHelper.onBindViewHolder(holder);
63         final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
64         if (restrictedIcon != null) {
65             restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
66         }
67     }
68 
69     @Override
performClick()70     public void performClick() {
71         if (!mHelper.performClick()) {
72             super.performClick();
73         }
74     }
75 
76     @Override
setEnabled(boolean enabled)77     public void setEnabled(boolean enabled) {
78         if (enabled && isDisabledByAdmin()) {
79             mHelper.setDisabledByAdmin(null);
80             return;
81         }
82         super.setEnabled(enabled);
83     }
84 
setDisabledByAdmin(EnforcedAdmin admin)85     public void setDisabledByAdmin(EnforcedAdmin admin) {
86         if (mHelper.setDisabledByAdmin(admin)) {
87             notifyChanged();
88         }
89     }
90 
isDisabledByAdmin()91     public boolean isDisabledByAdmin() {
92         return mHelper.isDisabledByAdmin();
93     }
94 
isRestrictedForEntry(CharSequence entry)95     public boolean isRestrictedForEntry(CharSequence entry) {
96         if (entry == null) {
97             return false;
98         }
99         for (RestrictedItem item : mRestrictedItems) {
100             if (entry.equals(item.entry)) {
101                 return true;
102             }
103         }
104         return false;
105     }
106 
addRestrictedItem(RestrictedItem item)107     public void addRestrictedItem(RestrictedItem item) {
108         mRestrictedItems.add(item);
109     }
110 
clearRestrictedItems()111     public void clearRestrictedItems() {
112         mRestrictedItems.clear();
113     }
114 
getRestrictedItemForEntryValue(CharSequence entryValue)115     private RestrictedItem getRestrictedItemForEntryValue(CharSequence entryValue) {
116         if (entryValue == null) {
117             return null;
118         }
119         for (RestrictedItem item : mRestrictedItems) {
120             if (entryValue.equals(item.entryValue)) {
121                 return item;
122             }
123         }
124         return null;
125     }
126 
createListAdapter()127     protected ListAdapter createListAdapter() {
128         return new RestrictedArrayAdapter(getContext(), getEntries(),
129                 getSelectedValuePos());
130     }
131 
getSelectedValuePos()132     public int getSelectedValuePos() {
133         final String selectedValue = getValue();
134         final int selectedIndex =
135                 (selectedValue == null) ? -1 : findIndexOfValue(selectedValue);
136         return selectedIndex;
137     }
138 
139     @Override
onPrepareDialogBuilder(AlertDialog.Builder builder, DialogInterface.OnClickListener listener)140     protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
141             DialogInterface.OnClickListener listener) {
142         builder.setAdapter(createListAdapter(), listener);
143     }
144 
145 
146     public class RestrictedArrayAdapter extends ArrayAdapter<CharSequence> {
147         private final int mSelectedIndex;
RestrictedArrayAdapter(Context context, CharSequence[] objects, int selectedIndex)148         public RestrictedArrayAdapter(Context context, CharSequence[] objects, int selectedIndex) {
149             super(context, R.layout.restricted_dialog_singlechoice, R.id.text1, objects);
150             mSelectedIndex = selectedIndex;
151         }
152 
153         @Override
getView(int position, View convertView, ViewGroup parent)154         public View getView(int position, View convertView, ViewGroup parent) {
155             View root = super.getView(position, convertView, parent);
156             CharSequence entry = getItem(position);
157             CheckedTextView text = (CheckedTextView) root.findViewById(R.id.text1);
158             ImageView padlock = (ImageView) root.findViewById(R.id.restricted_lock_icon);
159             if (isRestrictedForEntry(entry)) {
160                 text.setEnabled(false);
161                 text.setChecked(false);
162                 padlock.setVisibility(View.VISIBLE);
163             } else {
164                 if (mSelectedIndex != -1) {
165                     text.setChecked(position == mSelectedIndex);
166                 }
167                 if (!text.isEnabled()) {
168                     text.setEnabled(true);
169                 }
170                 padlock.setVisibility(View.GONE);
171             }
172             return root;
173         }
174 
175         @Override
hasStableIds()176         public boolean hasStableIds() {
177             return true;
178         }
179 
180         @Override
getItemId(int position)181         public long getItemId(int position) {
182             return position;
183         }
184     }
185 
186     public static class RestrictedListPreferenceDialogFragment extends
187             CustomListPreference.CustomListPreferenceDialogFragment {
188         private int mLastCheckedPosition = AdapterView.INVALID_POSITION;
189 
newInstance(String key)190         public static ListPreferenceDialogFragment newInstance(String key) {
191             final ListPreferenceDialogFragment fragment
192                     = new RestrictedListPreferenceDialogFragment();
193             final Bundle b = new Bundle(1);
194             b.putString(ARG_KEY, key);
195             fragment.setArguments(b);
196             return fragment;
197         }
198 
getCustomizablePreference()199         private RestrictedListPreference getCustomizablePreference() {
200             return (RestrictedListPreference) getPreference();
201         }
202 
203         @Override
getOnItemClickListener()204         protected DialogInterface.OnClickListener getOnItemClickListener() {
205             return new DialogInterface.OnClickListener() {
206                 public void onClick(DialogInterface dialog, int which) {
207                     final RestrictedListPreference preference = getCustomizablePreference();
208                     if (which < 0 || which >= preference.getEntryValues().length) {
209                         return;
210                     }
211                     String entryValue = preference.getEntryValues()[which].toString();
212                     RestrictedItem item = preference.getRestrictedItemForEntryValue(entryValue);
213                     if (item != null) {
214                         ListView listView = ((AlertDialog) dialog).getListView();
215                         listView.setItemChecked(getLastCheckedPosition(), true);
216                         RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
217                                 item.enforcedAdmin);
218                     } else {
219                         setClickedDialogEntryIndex(which);
220                     }
221 
222                     if (getCustomizablePreference().isAutoClosePreference()) {
223                         /*
224                          * Clicking on an item simulates the positive button
225                          * click, and dismisses the dialog.
226                          */
227                         RestrictedListPreferenceDialogFragment.this.onClick(dialog,
228                                 DialogInterface.BUTTON_POSITIVE);
229                         dialog.dismiss();
230                     }
231                 }
232             };
233         }
234 
getLastCheckedPosition()235         private int getLastCheckedPosition() {
236             if (mLastCheckedPosition == AdapterView.INVALID_POSITION) {
237                 mLastCheckedPosition = ((RestrictedListPreference) getCustomizablePreference())
238                         .getSelectedValuePos();
239             }
240             return mLastCheckedPosition;
241         }
242 
setCheckedPosition(int checkedPosition)243         private void setCheckedPosition(int checkedPosition) {
244             mLastCheckedPosition = checkedPosition;
245         }
246 
247         @Override
setClickedDialogEntryIndex(int which)248         protected void setClickedDialogEntryIndex(int which) {
249             super.setClickedDialogEntryIndex(which);
250             mLastCheckedPosition = which;
251         }
252     }
253 
254     public static class RestrictedItem {
255         public final CharSequence entry;
256         public final CharSequence entryValue;
257         public final EnforcedAdmin enforcedAdmin;
258 
259         public RestrictedItem(CharSequence entry, CharSequence entryValue,
260                 EnforcedAdmin enforcedAdmin) {
261             this.entry = entry;
262             this.entryValue = entryValue;
263             this.enforcedAdmin = enforcedAdmin;
264         }
265     }
266 }