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