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