1 /* 2 * Copyright (C) 2013 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 android.content; 18 19 import android.annotation.ArrayRes; 20 import android.annotation.Nullable; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 import java.util.Arrays; 25 import java.util.Objects; 26 27 /** 28 * Applications can expose restrictions for a restricted user on a 29 * multiuser device. The administrator can configure these restrictions that will then be 30 * applied to the restricted user. Each RestrictionsEntry is one configurable restriction. 31 * <p/> 32 * Any application that chooses to expose such restrictions does so by implementing a 33 * receiver that handles the {@link Intent#ACTION_GET_RESTRICTION_ENTRIES} action. 34 * The receiver then returns a result bundle that contains an entry called "restrictions", whose 35 * value is an ArrayList<RestrictionsEntry>. 36 */ 37 public class RestrictionEntry implements Parcelable { 38 39 /** 40 * Hidden restriction type. Use this type for information that needs to be transferred 41 * across but shouldn't be presented to the user in the UI. Stores a single String value. 42 */ 43 public static final int TYPE_NULL = 0; 44 45 /** 46 * Restriction of type "bool". Use this for storing a boolean value, typically presented as 47 * a checkbox in the UI. 48 */ 49 public static final int TYPE_BOOLEAN = 1; 50 51 /** 52 * Restriction of type "choice". Use this for storing a string value, typically presented as 53 * a single-select list. Call {@link #setChoiceEntries(String[])} and 54 * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user 55 * and the corresponding values, respectively. 56 */ 57 public static final int TYPE_CHOICE = 2; 58 59 /** 60 * Internal restriction type. Use this for storing a string value, typically presented as 61 * a single-select list. Call {@link #setChoiceEntries(String[])} and 62 * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user 63 * and the corresponding values, respectively. 64 * The presentation could imply that values in lower array indices are included when a 65 * particular value is chosen. 66 * @hide 67 */ 68 public static final int TYPE_CHOICE_LEVEL = 3; 69 70 /** 71 * Restriction of type "multi-select". Use this for presenting a multi-select list where more 72 * than one entry can be selected, such as for choosing specific titles to allowlist. 73 * Call {@link #setChoiceEntries(String[])} and 74 * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user 75 * and the corresponding values, respectively. 76 * Use {@link #getAllSelectedStrings()} and {@link #setAllSelectedStrings(String[])} to 77 * manipulate the selections. 78 */ 79 public static final int TYPE_MULTI_SELECT = 4; 80 81 /** 82 * Restriction of type "integer". Use this for storing an integer value. The range of values 83 * is from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}. 84 */ 85 public static final int TYPE_INTEGER = 5; 86 87 /** 88 * Restriction of type "string". Use this for storing a string value. 89 * @see #setSelectedString 90 * @see #getSelectedString 91 */ 92 public static final int TYPE_STRING = 6; 93 94 /** 95 * Restriction of type "bundle". Use this for storing {@link android.os.Bundle bundles} of 96 * restrictions 97 */ 98 public static final int TYPE_BUNDLE = 7; 99 100 /** 101 * Restriction of type "bundle_array". Use this for storing arrays of 102 * {@link android.os.Bundle bundles} of restrictions 103 */ 104 public static final int TYPE_BUNDLE_ARRAY = 8; 105 106 /** The type of restriction. */ 107 private int mType; 108 109 /** The unique key that identifies the restriction. */ 110 private String mKey; 111 112 /** The user-visible title of the restriction. */ 113 private String mTitle; 114 115 /** The user-visible secondary description of the restriction. */ 116 private String mDescription; 117 118 /** The user-visible set of choices used for single-select and multi-select lists. */ 119 private String[] mChoiceEntries; 120 121 /** The values corresponding to the user-visible choices. The value(s) of this entry will 122 * one or more of these, returned by {@link #getAllSelectedStrings()} and 123 * {@link #getSelectedString()}. 124 */ 125 private String[] mChoiceValues; 126 127 /* The chosen value, whose content depends on the type of the restriction. */ 128 private String mCurrentValue; 129 130 /* List of selected choices in the multi-select case. */ 131 private String[] mCurrentValues; 132 133 /** 134 * List of nested restrictions. Used by {@link #TYPE_BUNDLE bundle} and 135 * {@link #TYPE_BUNDLE_ARRAY bundle_array} restrictions. 136 */ 137 private RestrictionEntry[] mRestrictions; 138 139 /** 140 * Constructor for specifying the type and key, with no initial value; 141 * 142 * @param type the restriction type. 143 * @param key the unique key for this restriction 144 */ RestrictionEntry(int type, String key)145 public RestrictionEntry(int type, String key) { 146 mType = type; 147 mKey = key; 148 } 149 150 /** 151 * Constructor for {@link #TYPE_CHOICE} type. 152 * @param key the unique key for this restriction 153 * @param selectedString the current value 154 */ RestrictionEntry(String key, String selectedString)155 public RestrictionEntry(String key, String selectedString) { 156 this.mKey = key; 157 this.mType = TYPE_CHOICE; 158 this.mCurrentValue = selectedString; 159 } 160 161 /** 162 * Constructor for {@link #TYPE_BOOLEAN} type. 163 * @param key the unique key for this restriction 164 * @param selectedState whether this restriction is selected or not 165 */ RestrictionEntry(String key, boolean selectedState)166 public RestrictionEntry(String key, boolean selectedState) { 167 this.mKey = key; 168 this.mType = TYPE_BOOLEAN; 169 setSelectedState(selectedState); 170 } 171 172 /** 173 * Constructor for {@link #TYPE_MULTI_SELECT} type. 174 * @param key the unique key for this restriction 175 * @param selectedStrings the list of values that are currently selected 176 */ RestrictionEntry(String key, String[] selectedStrings)177 public RestrictionEntry(String key, String[] selectedStrings) { 178 this.mKey = key; 179 this.mType = TYPE_MULTI_SELECT; 180 this.mCurrentValues = selectedStrings; 181 } 182 183 /** 184 * Constructor for {@link #TYPE_INTEGER} type. 185 * @param key the unique key for this restriction 186 * @param selectedInt the integer value of the restriction 187 */ RestrictionEntry(String key, int selectedInt)188 public RestrictionEntry(String key, int selectedInt) { 189 mKey = key; 190 mType = TYPE_INTEGER; 191 setIntValue(selectedInt); 192 } 193 194 /** 195 * Constructor for {@link #TYPE_BUNDLE}/{@link #TYPE_BUNDLE_ARRAY} type. 196 * @param key the unique key for this restriction 197 * @param restrictionEntries array of nested restriction entries. If the entry, being created 198 * represents a {@link #TYPE_BUNDLE_ARRAY bundle-array}, {@code restrictionEntries} array may 199 * only contain elements of type {@link #TYPE_BUNDLE bundle}. 200 * @param isBundleArray true if this restriction represents 201 * {@link #TYPE_BUNDLE_ARRAY bundle-array} type, otherwise the type will be set to 202 * {@link #TYPE_BUNDLE bundle}. 203 */ RestrictionEntry(String key, RestrictionEntry[] restrictionEntries, boolean isBundleArray)204 private RestrictionEntry(String key, RestrictionEntry[] restrictionEntries, 205 boolean isBundleArray) { 206 mKey = key; 207 if (isBundleArray) { 208 mType = TYPE_BUNDLE_ARRAY; 209 if (restrictionEntries != null) { 210 for (RestrictionEntry restriction : restrictionEntries) { 211 if (restriction.getType() != TYPE_BUNDLE) { 212 throw new IllegalArgumentException("bundle_array restriction can only have " 213 + "nested restriction entries of type bundle"); 214 } 215 } 216 } 217 } else { 218 mType = TYPE_BUNDLE; 219 } 220 setRestrictions(restrictionEntries); 221 } 222 223 /** 224 * Creates an entry of type {@link #TYPE_BUNDLE}. 225 * @param key the unique key for this restriction 226 * @param restrictionEntries array of nested restriction entries. 227 * @return the newly created restriction 228 */ createBundleEntry(String key, RestrictionEntry[] restrictionEntries)229 public static RestrictionEntry createBundleEntry(String key, 230 RestrictionEntry[] restrictionEntries) { 231 return new RestrictionEntry(key, restrictionEntries, false); 232 } 233 234 /** 235 * Creates an entry of type {@link #TYPE_BUNDLE_ARRAY}. 236 * @param key the unique key for this restriction 237 * @param restrictionEntries array of nested restriction entries. The array may only contain 238 * elements of type {@link #TYPE_BUNDLE bundle}. 239 * @return the newly created restriction 240 */ createBundleArrayEntry(String key, RestrictionEntry[] restrictionEntries)241 public static RestrictionEntry createBundleArrayEntry(String key, 242 RestrictionEntry[] restrictionEntries) { 243 return new RestrictionEntry(key, restrictionEntries, true); 244 } 245 246 /** 247 * Sets the type for this restriction. 248 * @param type the type for this restriction. 249 */ setType(int type)250 public void setType(int type) { 251 this.mType = type; 252 } 253 254 /** 255 * Returns the type for this restriction. 256 * @return the type for this restriction 257 */ getType()258 public int getType() { 259 return mType; 260 } 261 262 /** 263 * Returns the currently selected string value. 264 * @return the currently selected value, which can be null for types that aren't for holding 265 * single string values. 266 */ getSelectedString()267 public String getSelectedString() { 268 return mCurrentValue; 269 } 270 271 /** 272 * Returns the list of currently selected values. 273 * @return the list of current selections, if type is {@link #TYPE_MULTI_SELECT}, 274 * null otherwise. 275 */ getAllSelectedStrings()276 public String[] getAllSelectedStrings() { 277 return mCurrentValues; 278 } 279 280 /** 281 * Returns the current selected state for an entry of type {@link #TYPE_BOOLEAN}. 282 * @return the current selected state of the entry. 283 */ getSelectedState()284 public boolean getSelectedState() { 285 return Boolean.parseBoolean(mCurrentValue); 286 } 287 288 /** 289 * Returns the value of the entry as an integer when the type is {@link #TYPE_INTEGER}. 290 * @return the integer value of the entry. 291 */ getIntValue()292 public int getIntValue() { 293 return Integer.parseInt(mCurrentValue); 294 } 295 296 /** 297 * Sets the integer value of the entry when the type is {@link #TYPE_INTEGER}. 298 * @param value the integer value to set. 299 */ setIntValue(int value)300 public void setIntValue(int value) { 301 mCurrentValue = Integer.toString(value); 302 } 303 304 /** 305 * Sets the string value to use as the selected value for this restriction. This value will 306 * be persisted by the system for later use by the application. 307 * @param selectedString the string value to select. 308 */ setSelectedString(String selectedString)309 public void setSelectedString(String selectedString) { 310 mCurrentValue = selectedString; 311 } 312 313 /** 314 * Sets the current selected state for an entry of type {@link #TYPE_BOOLEAN}. This value will 315 * be persisted by the system for later use by the application. 316 * @param state the current selected state 317 */ setSelectedState(boolean state)318 public void setSelectedState(boolean state) { 319 mCurrentValue = Boolean.toString(state); 320 } 321 322 /** 323 * Sets the current list of selected values for an entry of type {@link #TYPE_MULTI_SELECT}. 324 * These values will be persisted by the system for later use by the application. 325 * @param allSelectedStrings the current list of selected values. 326 */ setAllSelectedStrings(String[] allSelectedStrings)327 public void setAllSelectedStrings(String[] allSelectedStrings) { 328 mCurrentValues = allSelectedStrings; 329 } 330 331 /** 332 * Sets a list of string values that can be selected by the user. If no user-visible entries 333 * are set by a call to {@link #setChoiceEntries(String[])}, these values will be the ones 334 * shown to the user. Values will be chosen from this list as the user's selection and the 335 * selected values can be retrieved by a call to {@link #getAllSelectedStrings()}, or 336 * {@link #getSelectedString()}, depending on whether it is a multi-select type or choice type. 337 * This method is not relevant for types other than 338 * {@link #TYPE_CHOICE}, and {@link #TYPE_MULTI_SELECT}. 339 * @param choiceValues an array of Strings which will be the selected values for the user's 340 * selections. 341 * @see #getChoiceValues() 342 * @see #getAllSelectedStrings() 343 */ setChoiceValues(String[] choiceValues)344 public void setChoiceValues(String[] choiceValues) { 345 mChoiceValues = choiceValues; 346 } 347 348 /** 349 * Sets a list of string values that can be selected by the user, similar to 350 * {@link #setChoiceValues(String[])}. 351 * @param context the application context for retrieving the resources. 352 * @param stringArrayResId the resource id for a string array containing the possible values. 353 * @see #setChoiceValues(String[]) 354 */ setChoiceValues(Context context, @ArrayRes int stringArrayResId)355 public void setChoiceValues(Context context, @ArrayRes int stringArrayResId) { 356 mChoiceValues = context.getResources().getStringArray(stringArrayResId); 357 } 358 359 /** 360 * Returns array of possible restriction entries that this entry may contain. 361 */ getRestrictions()362 public RestrictionEntry[] getRestrictions() { 363 return mRestrictions; 364 } 365 366 /** 367 * Sets an array of possible restriction entries, that this entry may contain. 368 * <p>This method is only relevant for types {@link #TYPE_BUNDLE} and 369 * {@link #TYPE_BUNDLE_ARRAY} 370 */ setRestrictions(RestrictionEntry[] restrictions)371 public void setRestrictions(RestrictionEntry[] restrictions) { 372 mRestrictions = restrictions; 373 } 374 375 /** 376 * Returns the list of possible string values set earlier. 377 * @return the list of possible values. 378 */ getChoiceValues()379 public String[] getChoiceValues() { 380 return mChoiceValues; 381 } 382 383 /** 384 * Sets a list of strings that will be presented as choices to the user. When the 385 * user selects one or more of these choices, the corresponding value from the possible values 386 * are stored as the selected strings. The size of this array must match the size of the array 387 * set in {@link #setChoiceValues(String[])}. This method is not relevant for types other 388 * than {@link #TYPE_CHOICE}, and {@link #TYPE_MULTI_SELECT}. 389 * @param choiceEntries the list of user-visible choices. 390 * @see #setChoiceValues(String[]) 391 */ setChoiceEntries(String[] choiceEntries)392 public void setChoiceEntries(String[] choiceEntries) { 393 mChoiceEntries = choiceEntries; 394 } 395 396 /** Sets a list of strings that will be presented as choices to the user. This is similar to 397 * {@link #setChoiceEntries(String[])}. 398 * @param context the application context, used for retrieving the resources. 399 * @param stringArrayResId the resource id of a string array containing the possible entries. 400 */ setChoiceEntries(Context context, @ArrayRes int stringArrayResId)401 public void setChoiceEntries(Context context, @ArrayRes int stringArrayResId) { 402 mChoiceEntries = context.getResources().getStringArray(stringArrayResId); 403 } 404 405 /** 406 * Returns the list of strings, set earlier, that will be presented as choices to the user. 407 * @return the list of choices presented to the user. 408 */ getChoiceEntries()409 public String[] getChoiceEntries() { 410 return mChoiceEntries; 411 } 412 413 /** 414 * Returns the provided user-visible description of the entry, if any. 415 * @return the user-visible description, null if none was set earlier. 416 */ getDescription()417 public String getDescription() { 418 return mDescription; 419 } 420 421 /** 422 * Sets the user-visible description of the entry, as a possible sub-text for the title. 423 * You can use this to describe the entry in more detail or to display the current state of 424 * the restriction. 425 * @param description the user-visible description string. 426 */ setDescription(String description)427 public void setDescription(String description) { 428 this.mDescription = description; 429 } 430 431 /** 432 * This is the unique key for the restriction entry. 433 * @return the key for the restriction. 434 */ getKey()435 public String getKey() { 436 return mKey; 437 } 438 439 /** 440 * Returns the user-visible title for the entry, if any. 441 * @return the user-visible title for the entry, null if none was set earlier. 442 */ getTitle()443 public String getTitle() { 444 return mTitle; 445 } 446 447 /** 448 * Sets the user-visible title for the entry. 449 * @param title the user-visible title for the entry. 450 */ setTitle(String title)451 public void setTitle(String title) { 452 this.mTitle = title; 453 } 454 455 @Override equals(@ullable Object o)456 public boolean equals(@Nullable Object o) { 457 if (o == this) return true; 458 if (!(o instanceof RestrictionEntry)) return false; 459 final RestrictionEntry other = (RestrictionEntry) o; 460 if (mType != other.mType || !mKey.equals(other.mKey)) { 461 return false; 462 } 463 if (mCurrentValues == null && other.mCurrentValues == null 464 && mRestrictions == null && other.mRestrictions == null 465 && Objects.equals(mCurrentValue, other.mCurrentValue)) { 466 return true; 467 } 468 if (mCurrentValue == null && other.mCurrentValue == null 469 && mRestrictions == null && other.mRestrictions == null 470 && Arrays.equals(mCurrentValues, other.mCurrentValues)) { 471 return true; 472 } 473 if (mCurrentValue == null && other.mCurrentValue == null 474 && mCurrentValue == null && other.mCurrentValue == null 475 && Arrays.equals(mRestrictions, other.mRestrictions)) { 476 return true; 477 } 478 return false; 479 } 480 481 @Override hashCode()482 public int hashCode() { 483 int result = 17; 484 result = 31 * result + mKey.hashCode(); 485 if (mCurrentValue != null) { 486 result = 31 * result + mCurrentValue.hashCode(); 487 } else if (mCurrentValues != null) { 488 for (String value : mCurrentValues) { 489 if (value != null) { 490 result = 31 * result + value.hashCode(); 491 } 492 } 493 } else if (mRestrictions != null) { 494 result = 31 * result + Arrays.hashCode(mRestrictions); 495 } 496 return result; 497 } 498 RestrictionEntry(Parcel in)499 public RestrictionEntry(Parcel in) { 500 mType = in.readInt(); 501 mKey = in.readString(); 502 mTitle = in.readString(); 503 mDescription = in.readString(); 504 mChoiceEntries = in.readStringArray(); 505 mChoiceValues = in.readStringArray(); 506 mCurrentValue = in.readString(); 507 mCurrentValues = in.readStringArray(); 508 Parcelable[] parcelables = in.readParcelableArray(null, RestrictionEntry.class); 509 if (parcelables != null) { 510 mRestrictions = new RestrictionEntry[parcelables.length]; 511 for (int i = 0; i < parcelables.length; i++) { 512 mRestrictions[i] = (RestrictionEntry) parcelables[i]; 513 } 514 } 515 } 516 517 @Override describeContents()518 public int describeContents() { 519 return 0; 520 } 521 522 @Override writeToParcel(Parcel dest, int flags)523 public void writeToParcel(Parcel dest, int flags) { 524 dest.writeInt(mType); 525 dest.writeString(mKey); 526 dest.writeString(mTitle); 527 dest.writeString(mDescription); 528 dest.writeStringArray(mChoiceEntries); 529 dest.writeStringArray(mChoiceValues); 530 dest.writeString(mCurrentValue); 531 dest.writeStringArray(mCurrentValues); 532 dest.writeParcelableArray(mRestrictions, 0); 533 } 534 535 public static final @android.annotation.NonNull Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() { 536 public RestrictionEntry createFromParcel(Parcel source) { 537 return new RestrictionEntry(source); 538 } 539 540 public RestrictionEntry[] newArray(int size) { 541 return new RestrictionEntry[size]; 542 } 543 }; 544 545 @Override toString()546 public String toString() { 547 return "RestrictionEntry{" + 548 "mType=" + mType + 549 ", mKey='" + mKey + '\'' + 550 ", mTitle='" + mTitle + '\'' + 551 ", mDescription='" + mDescription + '\'' + 552 ", mChoiceEntries=" + Arrays.toString(mChoiceEntries) + 553 ", mChoiceValues=" + Arrays.toString(mChoiceValues) + 554 ", mCurrentValue='" + mCurrentValue + '\'' + 555 ", mCurrentValues=" + Arrays.toString(mCurrentValues) + 556 ", mRestrictions=" + Arrays.toString(mRestrictions) + 557 '}'; 558 } 559 } 560