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