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;
18
19import android.app.AlertDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.os.Bundle;
23import android.support.v14.preference.ListPreferenceDialogFragment;
24import android.support.v7.preference.PreferenceViewHolder;
25import android.util.AttributeSet;
26import android.view.View;
27import android.view.ViewGroup;
28import android.widget.AdapterView;
29import android.widget.ArrayAdapter;
30import android.widget.CheckedTextView;
31import android.widget.ImageView;
32import android.widget.ListAdapter;
33import android.widget.ListView;
34
35import com.android.settingslib.RestrictedLockUtils;
36import com.android.settingslib.RestrictedPreferenceHelper;
37
38import java.util.ArrayList;
39import java.util.List;
40
41import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
42
43public class RestrictedListPreference extends CustomListPreference {
44    private final RestrictedPreferenceHelper mHelper;
45    private final List<RestrictedItem> mRestrictedItems = new ArrayList<>();
46
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
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
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
70    public void performClick() {
71        if (!mHelper.performClick()) {
72            super.performClick();
73        }
74    }
75
76    @Override
77    public void setEnabled(boolean enabled) {
78        if (enabled && isDisabledByAdmin()) {
79            mHelper.setDisabledByAdmin(null);
80            return;
81        }
82        super.setEnabled(enabled);
83    }
84
85    public void setDisabledByAdmin(EnforcedAdmin admin) {
86        if (mHelper.setDisabledByAdmin(admin)) {
87            notifyChanged();
88        }
89    }
90
91    public boolean isDisabledByAdmin() {
92        return mHelper.isDisabledByAdmin();
93    }
94
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
107    public void addRestrictedItem(RestrictedItem item) {
108        mRestrictedItems.add(item);
109    }
110
111    public void clearRestrictedItems() {
112        mRestrictedItems.clear();
113    }
114
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
127    protected ListAdapter createListAdapter() {
128        return new RestrictedArrayAdapter(getContext(), getEntries(),
129                getSelectedValuePos());
130    }
131
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
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;
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
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
176        public boolean hasStableIds() {
177            return true;
178        }
179
180        @Override
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
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
199        private RestrictedListPreference getCustomizablePreference() {
200            return (RestrictedListPreference) getPreference();
201        }
202
203        @Override
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
235        private int getLastCheckedPosition() {
236            if (mLastCheckedPosition == AdapterView.INVALID_POSITION) {
237                mLastCheckedPosition = ((RestrictedListPreference) getCustomizablePreference())
238                        .getSelectedValuePos();
239            }
240            return mLastCheckedPosition;
241        }
242
243        private void setCheckedPosition(int checkedPosition) {
244            mLastCheckedPosition = checkedPosition;
245        }
246
247        @Override
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}