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