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