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.notification; 18 19 import android.content.Context; 20 import android.graphics.drawable.Drawable; 21 import android.support.v7.preference.DropDownPreference; 22 import android.support.v7.preference.PreferenceViewHolder; 23 import android.util.AttributeSet; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.widget.AdapterView; 27 import android.widget.AdapterView.OnItemSelectedListener; 28 import android.widget.ArrayAdapter; 29 import android.widget.Spinner; 30 import android.widget.TextView; 31 32 import com.android.settings.R; 33 import com.android.settingslib.RestrictedLockUtils; 34 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 35 import com.android.settingslib.RestrictedPreferenceHelper; 36 37 import java.util.ArrayList; 38 import java.util.List; 39 40 public 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 }