Loading api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -8379,6 +8379,7 @@ package android.content { ctor public RestrictionEntry(java.lang.String, boolean); ctor public RestrictionEntry(java.lang.String, java.lang.String[]); ctor public RestrictionEntry(java.lang.String, int); ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean); ctor public RestrictionEntry(android.os.Parcel); method public int describeContents(); method public java.lang.String[] getAllSelectedStrings(); Loading @@ -8387,6 +8388,7 @@ package android.content { method public java.lang.String getDescription(); method public int getIntValue(); method public java.lang.String getKey(); method public android.content.RestrictionEntry[] getRestrictions(); method public boolean getSelectedState(); method public java.lang.String getSelectedString(); method public java.lang.String getTitle(); Loading @@ -8398,6 +8400,7 @@ package android.content { method public void setChoiceValues(android.content.Context, int); method public void setDescription(java.lang.String); method public void setIntValue(int); method public void setRestrictions(android.content.RestrictionEntry[]); method public void setSelectedState(boolean); method public void setSelectedString(java.lang.String); method public void setTitle(java.lang.String); Loading @@ -8405,6 +8408,8 @@ package android.content { method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR; field public static final int TYPE_BOOLEAN = 1; // 0x1 field public static final int TYPE_BUNDLE = 7; // 0x7 field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8 field public static final int TYPE_CHOICE = 2; // 0x2 field public static final int TYPE_INTEGER = 5; // 0x5 field public static final int TYPE_MULTI_SELECT = 4; // 0x4 Loading @@ -8413,6 +8418,7 @@ package android.content { } public class RestrictionsManager { method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>); method public android.content.Intent createLocalApprovalIntent(); method public android.os.Bundle getApplicationRestrictions(); method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String); api/system-current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -8600,6 +8600,7 @@ package android.content { ctor public RestrictionEntry(java.lang.String, boolean); ctor public RestrictionEntry(java.lang.String, java.lang.String[]); ctor public RestrictionEntry(java.lang.String, int); ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean); ctor public RestrictionEntry(android.os.Parcel); method public int describeContents(); method public java.lang.String[] getAllSelectedStrings(); Loading @@ -8608,6 +8609,7 @@ package android.content { method public java.lang.String getDescription(); method public int getIntValue(); method public java.lang.String getKey(); method public android.content.RestrictionEntry[] getRestrictions(); method public boolean getSelectedState(); method public java.lang.String getSelectedString(); method public java.lang.String getTitle(); Loading @@ -8619,6 +8621,7 @@ package android.content { method public void setChoiceValues(android.content.Context, int); method public void setDescription(java.lang.String); method public void setIntValue(int); method public void setRestrictions(android.content.RestrictionEntry[]); method public void setSelectedState(boolean); method public void setSelectedString(java.lang.String); method public void setTitle(java.lang.String); Loading @@ -8626,6 +8629,8 @@ package android.content { method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR; field public static final int TYPE_BOOLEAN = 1; // 0x1 field public static final int TYPE_BUNDLE = 7; // 0x7 field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8 field public static final int TYPE_CHOICE = 2; // 0x2 field public static final int TYPE_INTEGER = 5; // 0x5 field public static final int TYPE_MULTI_SELECT = 4; // 0x4 Loading @@ -8634,6 +8639,7 @@ package android.content { } public class RestrictionsManager { method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>); method public android.content.Intent createLocalApprovalIntent(); method public android.os.Bundle getApplicationRestrictions(); method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String); core/java/android/content/RestrictionEntry.java +123 −54 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ import android.annotation.ArrayRes; import android.os.Parcel; import android.os.Parcelable; import java.util.Arrays; import java.util.Objects; /** * Applications can expose restrictions for a restricted user on a * multiuser device. The administrator can configure these restrictions that will then be Loading @@ -33,19 +36,19 @@ import android.os.Parcelable; public class RestrictionEntry implements Parcelable { /** * A type of restriction. Use this type for information that needs to be transferred across * but shouldn't be presented to the user in the UI. Stores a single String value. * Hidden restriction type. Use this type for information that needs to be transferred * across but shouldn't be presented to the user in the UI. Stores a single String value. */ public static final int TYPE_NULL = 0; /** * A type of restriction. Use this for storing a boolean value, typically presented as * Restriction of type "bool". Use this for storing a boolean value, typically presented as * a checkbox in the UI. */ public static final int TYPE_BOOLEAN = 1; /** * A type of restriction. Use this for storing a string value, typically presented as * Restriction of type "choice". Use this for storing a string value, typically presented as * a single-select list. Call {@link #setChoiceEntries(String[])} and * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user * and the corresponding values, respectively. Loading @@ -53,7 +56,7 @@ public class RestrictionEntry implements Parcelable { public static final int TYPE_CHOICE = 2; /** * A type of restriction. Use this for storing a string value, typically presented as * Internal restriction type. Use this for storing a string value, typically presented as * a single-select list. Call {@link #setChoiceEntries(String[])} and * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user * and the corresponding values, respectively. Loading @@ -64,8 +67,8 @@ public class RestrictionEntry implements Parcelable { public static final int TYPE_CHOICE_LEVEL = 3; /** * A type of restriction. Use this for presenting a multi-select list where more than one * entry can be selected, such as for choosing specific titles to white-list. * Restriction of type "multi-select". Use this for presenting a multi-select list where more * than one entry can be selected, such as for choosing specific titles to white-list. * Call {@link #setChoiceEntries(String[])} and * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user * and the corresponding values, respectively. Loading @@ -75,18 +78,30 @@ public class RestrictionEntry implements Parcelable { public static final int TYPE_MULTI_SELECT = 4; /** * A type of restriction. Use this for storing an integer value. The range of values * Restriction of type "integer". Use this for storing an integer value. The range of values * is from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}. */ public static final int TYPE_INTEGER = 5; /** * A type of restriction. Use this for storing a string value. * Restriction of type "string". Use this for storing a string value. * @see #setSelectedString * @see #getSelectedString */ public static final int TYPE_STRING = 6; /** * Restriction of type "bundle". Use this for storing {@link android.os.Bundle bundles} of * restrictions */ public static final int TYPE_BUNDLE = 7; /** * Restriction of type "bundle_array". Use this for storing arrays of * {@link android.os.Bundle bundles} of restrictions */ public static final int TYPE_BUNDLE_ARRAY = 8; /** The type of restriction. */ private int mType; Loading Loading @@ -114,6 +129,12 @@ public class RestrictionEntry implements Parcelable { /* List of selected choices in the multi-select case. */ private String[] mCurrentValues; /** * List of nested restrictions. Used by {@link #TYPE_BUNDLE bundle} and * {@link #TYPE_BUNDLE_ARRAY bundle_array} restrictions. */ private RestrictionEntry[] mRestrictions; /** * Constructor for specifying the type and key, with no initial value; * Loading Loading @@ -169,6 +190,35 @@ public class RestrictionEntry implements Parcelable { setIntValue(selectedInt); } /** * Constructor for {@link #TYPE_BUNDLE}/{@link #TYPE_BUNDLE_ARRAY} type. * @param key the unique key for this restriction * @param restrictionEntries array of nested restriction entries. If the entry, being created * represents a {@link #TYPE_BUNDLE_ARRAY bundle-array}, {@code restrictionEntries} array may * only contain elements of type {@link #TYPE_BUNDLE bundle}. * @param isBundleArray true if this restriction represents * {@link #TYPE_BUNDLE_ARRAY bundle-array} type, otherwise the type will be set to * {@link #TYPE_BUNDLE bundle}. */ public RestrictionEntry(String key, RestrictionEntry[] restrictionEntries, boolean isBundleArray) { mKey = key; if (isBundleArray) { mType = TYPE_BUNDLE_ARRAY; if (restrictionEntries != null) { for (RestrictionEntry restriction : restrictionEntries) { if (restriction.getType() != TYPE_BUNDLE) { throw new IllegalArgumentException("bundle_array restriction can only have " + "nested restriction entries of type bundle"); } } } } else { mType = TYPE_BUNDLE; } setRestrictions(restrictionEntries); } /** * Sets the type for this restriction. * @param type the type for this restriction. Loading Loading @@ -282,6 +332,22 @@ public class RestrictionEntry implements Parcelable { mChoiceValues = context.getResources().getStringArray(stringArrayResId); } /** * Returns array of possible restriction entries that this entry may contain. */ public RestrictionEntry[] getRestrictions() { return mRestrictions; } /** * Sets an array of possible restriction entries, that this entry may contain. * <p>This method is only relevant for types {@link #TYPE_BUNDLE} and * {@link #TYPE_BUNDLE_ARRAY} */ public void setRestrictions(RestrictionEntry[] restrictions) { mRestrictions = restrictions; } /** * Returns the list of possible string values set earlier. * @return the list of possible values. Loading Loading @@ -362,27 +428,30 @@ public class RestrictionEntry implements Parcelable { this.mTitle = title; } private boolean equalArrays(String[] one, String[] other) { if (one.length != other.length) return false; for (int i = 0; i < one.length; i++) { if (!one[i].equals(other[i])) return false; } return true; } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof RestrictionEntry)) return false; final RestrictionEntry other = (RestrictionEntry) o; // Make sure that either currentValue matches or currentValues matches. return mType == other.mType && mKey.equals(other.mKey) && ((mCurrentValues == null && other.mCurrentValues == null && mCurrentValue != null && mCurrentValue.equals(other.mCurrentValue)) || (mCurrentValue == null && other.mCurrentValue == null && mCurrentValues != null && equalArrays(mCurrentValues, other.mCurrentValues))); if (mType != other.mType || mKey.equals(other.mKey)) { return false; } if (mCurrentValues == null && other.mCurrentValues == null && mRestrictions == null && other.mRestrictions == null && Objects.equals(mCurrentValue, other.mCurrentValue)) { return true; } if (mCurrentValue == null && other.mCurrentValue == null && mRestrictions == null && other.mRestrictions == null && Arrays.equals(mCurrentValues, other.mCurrentValues)) { return true; } if (mCurrentValue == null && other.mCurrentValue == null && mCurrentValue == null && other.mCurrentValue == null && Arrays.equals(mRestrictions, other.mRestrictions)) { return true; } return false; } @Override Loading @@ -397,28 +466,28 @@ public class RestrictionEntry implements Parcelable { result = 31 * result + value.hashCode(); } } } else if (mRestrictions != null) { result = 31 * result + Arrays.hashCode(mRestrictions); } return result; } private String[] readArray(Parcel in) { int count = in.readInt(); String[] values = new String[count]; for (int i = 0; i < count; i++) { values[i] = in.readString(); } return values; } public RestrictionEntry(Parcel in) { mType = in.readInt(); mKey = in.readString(); mTitle = in.readString(); mDescription = in.readString(); mChoiceEntries = readArray(in); mChoiceValues = readArray(in); mChoiceEntries = in.readStringArray(); mChoiceValues = in.readStringArray(); mCurrentValue = in.readString(); mCurrentValues = readArray(in); mCurrentValues = in.readStringArray(); Parcelable[] parcelables = in.readParcelableArray(null); if (parcelables != null) { mRestrictions = new RestrictionEntry[parcelables.length]; for (int i = 0; i < parcelables.length; i++) { mRestrictions[i] = (RestrictionEntry) parcelables[i]; } } } @Override Loading @@ -426,27 +495,17 @@ public class RestrictionEntry implements Parcelable { return 0; } private void writeArray(Parcel dest, String[] values) { if (values == null) { dest.writeInt(0); } else { dest.writeInt(values.length); for (int i = 0; i < values.length; i++) { dest.writeString(values[i]); } } } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); dest.writeString(mKey); dest.writeString(mTitle); dest.writeString(mDescription); writeArray(dest, mChoiceEntries); writeArray(dest, mChoiceValues); dest.writeStringArray(mChoiceEntries); dest.writeStringArray(mChoiceValues); dest.writeString(mCurrentValue); writeArray(dest, mCurrentValues); dest.writeStringArray(mCurrentValues); dest.writeParcelableArray(mRestrictions, 0); } public static final Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() { Loading @@ -461,6 +520,16 @@ public class RestrictionEntry implements Parcelable { @Override public String toString() { return "RestrictionsEntry {type=" + mType + ", key=" + mKey + ", value=" + mCurrentValue + "}"; return "RestrictionEntry{" + "mType=" + mType + ", mKey='" + mKey + '\'' + ", mTitle='" + mTitle + '\'' + ", mDescription='" + mDescription + '\'' + ", mChoiceEntries=" + Arrays.toString(mChoiceEntries) + ", mChoiceValues=" + Arrays.toString(mChoiceValues) + ", mCurrentValue='" + mCurrentValue + '\'' + ", mCurrentValues=" + Arrays.toString(mCurrentValues) + ", mRestrictions=" + Arrays.toString(mRestrictions) + '}'; } } core/java/android/content/RestrictionsManager.java +112 −18 Original line number Diff line number Diff line Loading @@ -32,12 +32,14 @@ import android.util.Log; import android.util.Xml; import com.android.internal.R; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -71,12 +73,15 @@ import java.util.List; * android:key="string" * android:title="string resource" * android:restrictionType=["bool" | "string" | "integer" * | "choice" | "multi-select" | "hidden"] * | "choice" | "multi-select" | "hidden" * | "bundle" | "bundle_array"] * android:description="string resource" * android:entries="string-array resource" * android:entryValues="string-array resource" * android:defaultValue="reference" * /> * android:defaultValue="reference" > * <restriction ... /> * ... * </restriction> * <restriction ... /> * ... * </restrictions> Loading @@ -97,6 +102,9 @@ import java.util.List; * administrator controlling the values, if the title is not sufficient.</li> * </ul> * <p> * Only restrictions of type {@code bundle} and {@code bundle_array} can have one or multiple nested * restriction elements. * <p> * In your manifest's <code>application</code> section, add the meta-data tag to point to * the restrictions XML file as shown below: * <pre> Loading Loading @@ -537,9 +545,7 @@ public class RestrictionsManager { XmlResourceParser xml = appInfo.loadXmlMetaData(mContext.getPackageManager(), META_DATA_APP_RESTRICTIONS); List<RestrictionEntry> restrictions = loadManifestRestrictions(packageName, xml); return restrictions; return loadManifestRestrictions(packageName, xml); } private List<RestrictionEntry> loadManifestRestrictions(String packageName, Loading @@ -550,25 +556,18 @@ public class RestrictionsManager { } catch (NameNotFoundException nnfe) { return null; } ArrayList<RestrictionEntry> restrictions = new ArrayList<RestrictionEntry>(); ArrayList<RestrictionEntry> restrictions = new ArrayList<>(); RestrictionEntry restriction; try { int tagType = xml.next(); while (tagType != XmlPullParser.END_DOCUMENT) { if (tagType == XmlPullParser.START_TAG) { if (xml.getName().equals(TAG_RESTRICTION)) { AttributeSet attrSet = Xml.asAttributeSet(xml); if (attrSet != null) { TypedArray a = appContext.obtainStyledAttributes(attrSet, com.android.internal.R.styleable.RestrictionEntry); restriction = loadRestriction(appContext, a); restriction = loadRestrictionElement(appContext, xml); if (restriction != null) { restrictions.add(restriction); } } } } tagType = xml.next(); } } catch (XmlPullParserException e) { Loading @@ -582,7 +581,21 @@ public class RestrictionsManager { return restrictions; } private RestrictionEntry loadRestriction(Context appContext, TypedArray a) { private RestrictionEntry loadRestrictionElement(Context appContext, XmlResourceParser xml) throws IOException, XmlPullParserException { if (xml.getName().equals(TAG_RESTRICTION)) { AttributeSet attrSet = Xml.asAttributeSet(xml); if (attrSet != null) { TypedArray a = appContext.obtainStyledAttributes(attrSet, com.android.internal.R.styleable.RestrictionEntry); return loadRestriction(appContext, a, xml); } } return null; } private RestrictionEntry loadRestriction(Context appContext, TypedArray a, XmlResourceParser xml) throws IOException, XmlPullParserException { String key = a.getString(R.styleable.RestrictionEntry_key); int restrictionType = a.getInt( R.styleable.RestrictionEntry_restrictionType, -1); Loading Loading @@ -633,9 +646,90 @@ public class RestrictionsManager { restriction.setSelectedState( a.getBoolean(R.styleable.RestrictionEntry_defaultValue, false)); break; case RestrictionEntry.TYPE_BUNDLE: case RestrictionEntry.TYPE_BUNDLE_ARRAY: final int outerDepth = xml.getDepth(); List<RestrictionEntry> restrictionEntries = new ArrayList<>(); while (XmlUtils.nextElementWithin(xml, outerDepth)) { RestrictionEntry childEntry = loadRestrictionElement(appContext, xml); if (childEntry == null) { Log.w(TAG, "Child entry cannot be loaded for bundle restriction " + key); } else { restrictionEntries.add(childEntry); if (restrictionType == RestrictionEntry.TYPE_BUNDLE_ARRAY && childEntry.getType() != RestrictionEntry.TYPE_BUNDLE) { Log.w(TAG, "bundle_array " + key + " can only contain entries of type bundle"); } } } restriction.setRestrictions(restrictionEntries.toArray(new RestrictionEntry[ restrictionEntries.size()])); break; default: Log.w(TAG, "Unknown restriction type " + restrictionType); } return restriction; } /** * Converts a list of restrictions to the corresponding bundle, using the following mapping: * <table> * <tr><th>RestrictionEntry</th><th>Bundle</th></tr> * <tr><td>{@link RestrictionEntry#TYPE_BOOLEAN}</td><td>{@link Bundle#putBoolean}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_CHOICE}, {@link RestrictionEntry#TYPE_CHOICE}</td> * <td>{@link Bundle#putStringArray}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_INTEGER}</td><td>{@link Bundle#putInt}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_STRING}</td><td>{@link Bundle#putString}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE}</td><td>{@link Bundle#putBundle}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE_ARRAY}</td> * <td>{@link Bundle#putParcelableArray}</td></tr> * </table> * @param entries list of restrictions */ public static Bundle convertRestrictionsToBundle(List<RestrictionEntry> entries) { final Bundle bundle = new Bundle(); for (RestrictionEntry entry : entries) { addRestrictionToBundle(bundle, entry); } return bundle; } private static Bundle addRestrictionToBundle(Bundle bundle, RestrictionEntry entry) { switch (entry.getType()) { case RestrictionEntry.TYPE_BOOLEAN: bundle.putBoolean(entry.getKey(), entry.getSelectedState()); break; case RestrictionEntry.TYPE_CHOICE: case RestrictionEntry.TYPE_CHOICE_LEVEL: case RestrictionEntry.TYPE_MULTI_SELECT: bundle.putStringArray(entry.getKey(), entry.getAllSelectedStrings()); break; case RestrictionEntry.TYPE_INTEGER: bundle.putInt(entry.getKey(), entry.getIntValue()); break; case RestrictionEntry.TYPE_STRING: case RestrictionEntry.TYPE_NULL: bundle.putString(entry.getKey(), entry.getSelectedString()); break; case RestrictionEntry.TYPE_BUNDLE: RestrictionEntry[] restrictions = entry.getRestrictions(); Bundle childBundle = convertRestrictionsToBundle(Arrays.asList(restrictions)); bundle.putBundle(entry.getKey(), childBundle); break; case RestrictionEntry.TYPE_BUNDLE_ARRAY: restrictions = entry.getRestrictions(); Bundle[] bundleArray = new Bundle[restrictions.length]; for (int i = 0; i < restrictions.length; i++) { bundleArray[i] = addRestrictionToBundle(new Bundle(), restrictions[i]); } bundle.putParcelableArray(entry.getKey(), bundleArray); break; default: throw new IllegalArgumentException( "Unsupported restrictionEntry type: " + entry.getType()); } return bundle; } } core/res/res/values/attrs.xml +2 −0 Original line number Diff line number Diff line Loading @@ -7759,6 +7759,8 @@ <enum name="multi-select" value="4" /> <enum name="integer" value="5" /> <enum name="string" value="6" /> <enum name="bundle" value="7" /> <enum name="bundle_array" value="8" /> </attr> <attr name="title" /> <attr name="description" /> Loading Loading
api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -8379,6 +8379,7 @@ package android.content { ctor public RestrictionEntry(java.lang.String, boolean); ctor public RestrictionEntry(java.lang.String, java.lang.String[]); ctor public RestrictionEntry(java.lang.String, int); ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean); ctor public RestrictionEntry(android.os.Parcel); method public int describeContents(); method public java.lang.String[] getAllSelectedStrings(); Loading @@ -8387,6 +8388,7 @@ package android.content { method public java.lang.String getDescription(); method public int getIntValue(); method public java.lang.String getKey(); method public android.content.RestrictionEntry[] getRestrictions(); method public boolean getSelectedState(); method public java.lang.String getSelectedString(); method public java.lang.String getTitle(); Loading @@ -8398,6 +8400,7 @@ package android.content { method public void setChoiceValues(android.content.Context, int); method public void setDescription(java.lang.String); method public void setIntValue(int); method public void setRestrictions(android.content.RestrictionEntry[]); method public void setSelectedState(boolean); method public void setSelectedString(java.lang.String); method public void setTitle(java.lang.String); Loading @@ -8405,6 +8408,8 @@ package android.content { method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR; field public static final int TYPE_BOOLEAN = 1; // 0x1 field public static final int TYPE_BUNDLE = 7; // 0x7 field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8 field public static final int TYPE_CHOICE = 2; // 0x2 field public static final int TYPE_INTEGER = 5; // 0x5 field public static final int TYPE_MULTI_SELECT = 4; // 0x4 Loading @@ -8413,6 +8418,7 @@ package android.content { } public class RestrictionsManager { method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>); method public android.content.Intent createLocalApprovalIntent(); method public android.os.Bundle getApplicationRestrictions(); method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
api/system-current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -8600,6 +8600,7 @@ package android.content { ctor public RestrictionEntry(java.lang.String, boolean); ctor public RestrictionEntry(java.lang.String, java.lang.String[]); ctor public RestrictionEntry(java.lang.String, int); ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean); ctor public RestrictionEntry(android.os.Parcel); method public int describeContents(); method public java.lang.String[] getAllSelectedStrings(); Loading @@ -8608,6 +8609,7 @@ package android.content { method public java.lang.String getDescription(); method public int getIntValue(); method public java.lang.String getKey(); method public android.content.RestrictionEntry[] getRestrictions(); method public boolean getSelectedState(); method public java.lang.String getSelectedString(); method public java.lang.String getTitle(); Loading @@ -8619,6 +8621,7 @@ package android.content { method public void setChoiceValues(android.content.Context, int); method public void setDescription(java.lang.String); method public void setIntValue(int); method public void setRestrictions(android.content.RestrictionEntry[]); method public void setSelectedState(boolean); method public void setSelectedString(java.lang.String); method public void setTitle(java.lang.String); Loading @@ -8626,6 +8629,8 @@ package android.content { method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR; field public static final int TYPE_BOOLEAN = 1; // 0x1 field public static final int TYPE_BUNDLE = 7; // 0x7 field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8 field public static final int TYPE_CHOICE = 2; // 0x2 field public static final int TYPE_INTEGER = 5; // 0x5 field public static final int TYPE_MULTI_SELECT = 4; // 0x4 Loading @@ -8634,6 +8639,7 @@ package android.content { } public class RestrictionsManager { method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>); method public android.content.Intent createLocalApprovalIntent(); method public android.os.Bundle getApplicationRestrictions(); method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
core/java/android/content/RestrictionEntry.java +123 −54 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ import android.annotation.ArrayRes; import android.os.Parcel; import android.os.Parcelable; import java.util.Arrays; import java.util.Objects; /** * Applications can expose restrictions for a restricted user on a * multiuser device. The administrator can configure these restrictions that will then be Loading @@ -33,19 +36,19 @@ import android.os.Parcelable; public class RestrictionEntry implements Parcelable { /** * A type of restriction. Use this type for information that needs to be transferred across * but shouldn't be presented to the user in the UI. Stores a single String value. * Hidden restriction type. Use this type for information that needs to be transferred * across but shouldn't be presented to the user in the UI. Stores a single String value. */ public static final int TYPE_NULL = 0; /** * A type of restriction. Use this for storing a boolean value, typically presented as * Restriction of type "bool". Use this for storing a boolean value, typically presented as * a checkbox in the UI. */ public static final int TYPE_BOOLEAN = 1; /** * A type of restriction. Use this for storing a string value, typically presented as * Restriction of type "choice". Use this for storing a string value, typically presented as * a single-select list. Call {@link #setChoiceEntries(String[])} and * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user * and the corresponding values, respectively. Loading @@ -53,7 +56,7 @@ public class RestrictionEntry implements Parcelable { public static final int TYPE_CHOICE = 2; /** * A type of restriction. Use this for storing a string value, typically presented as * Internal restriction type. Use this for storing a string value, typically presented as * a single-select list. Call {@link #setChoiceEntries(String[])} and * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user * and the corresponding values, respectively. Loading @@ -64,8 +67,8 @@ public class RestrictionEntry implements Parcelable { public static final int TYPE_CHOICE_LEVEL = 3; /** * A type of restriction. Use this for presenting a multi-select list where more than one * entry can be selected, such as for choosing specific titles to white-list. * Restriction of type "multi-select". Use this for presenting a multi-select list where more * than one entry can be selected, such as for choosing specific titles to white-list. * Call {@link #setChoiceEntries(String[])} and * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user * and the corresponding values, respectively. Loading @@ -75,18 +78,30 @@ public class RestrictionEntry implements Parcelable { public static final int TYPE_MULTI_SELECT = 4; /** * A type of restriction. Use this for storing an integer value. The range of values * Restriction of type "integer". Use this for storing an integer value. The range of values * is from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}. */ public static final int TYPE_INTEGER = 5; /** * A type of restriction. Use this for storing a string value. * Restriction of type "string". Use this for storing a string value. * @see #setSelectedString * @see #getSelectedString */ public static final int TYPE_STRING = 6; /** * Restriction of type "bundle". Use this for storing {@link android.os.Bundle bundles} of * restrictions */ public static final int TYPE_BUNDLE = 7; /** * Restriction of type "bundle_array". Use this for storing arrays of * {@link android.os.Bundle bundles} of restrictions */ public static final int TYPE_BUNDLE_ARRAY = 8; /** The type of restriction. */ private int mType; Loading Loading @@ -114,6 +129,12 @@ public class RestrictionEntry implements Parcelable { /* List of selected choices in the multi-select case. */ private String[] mCurrentValues; /** * List of nested restrictions. Used by {@link #TYPE_BUNDLE bundle} and * {@link #TYPE_BUNDLE_ARRAY bundle_array} restrictions. */ private RestrictionEntry[] mRestrictions; /** * Constructor for specifying the type and key, with no initial value; * Loading Loading @@ -169,6 +190,35 @@ public class RestrictionEntry implements Parcelable { setIntValue(selectedInt); } /** * Constructor for {@link #TYPE_BUNDLE}/{@link #TYPE_BUNDLE_ARRAY} type. * @param key the unique key for this restriction * @param restrictionEntries array of nested restriction entries. If the entry, being created * represents a {@link #TYPE_BUNDLE_ARRAY bundle-array}, {@code restrictionEntries} array may * only contain elements of type {@link #TYPE_BUNDLE bundle}. * @param isBundleArray true if this restriction represents * {@link #TYPE_BUNDLE_ARRAY bundle-array} type, otherwise the type will be set to * {@link #TYPE_BUNDLE bundle}. */ public RestrictionEntry(String key, RestrictionEntry[] restrictionEntries, boolean isBundleArray) { mKey = key; if (isBundleArray) { mType = TYPE_BUNDLE_ARRAY; if (restrictionEntries != null) { for (RestrictionEntry restriction : restrictionEntries) { if (restriction.getType() != TYPE_BUNDLE) { throw new IllegalArgumentException("bundle_array restriction can only have " + "nested restriction entries of type bundle"); } } } } else { mType = TYPE_BUNDLE; } setRestrictions(restrictionEntries); } /** * Sets the type for this restriction. * @param type the type for this restriction. Loading Loading @@ -282,6 +332,22 @@ public class RestrictionEntry implements Parcelable { mChoiceValues = context.getResources().getStringArray(stringArrayResId); } /** * Returns array of possible restriction entries that this entry may contain. */ public RestrictionEntry[] getRestrictions() { return mRestrictions; } /** * Sets an array of possible restriction entries, that this entry may contain. * <p>This method is only relevant for types {@link #TYPE_BUNDLE} and * {@link #TYPE_BUNDLE_ARRAY} */ public void setRestrictions(RestrictionEntry[] restrictions) { mRestrictions = restrictions; } /** * Returns the list of possible string values set earlier. * @return the list of possible values. Loading Loading @@ -362,27 +428,30 @@ public class RestrictionEntry implements Parcelable { this.mTitle = title; } private boolean equalArrays(String[] one, String[] other) { if (one.length != other.length) return false; for (int i = 0; i < one.length; i++) { if (!one[i].equals(other[i])) return false; } return true; } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof RestrictionEntry)) return false; final RestrictionEntry other = (RestrictionEntry) o; // Make sure that either currentValue matches or currentValues matches. return mType == other.mType && mKey.equals(other.mKey) && ((mCurrentValues == null && other.mCurrentValues == null && mCurrentValue != null && mCurrentValue.equals(other.mCurrentValue)) || (mCurrentValue == null && other.mCurrentValue == null && mCurrentValues != null && equalArrays(mCurrentValues, other.mCurrentValues))); if (mType != other.mType || mKey.equals(other.mKey)) { return false; } if (mCurrentValues == null && other.mCurrentValues == null && mRestrictions == null && other.mRestrictions == null && Objects.equals(mCurrentValue, other.mCurrentValue)) { return true; } if (mCurrentValue == null && other.mCurrentValue == null && mRestrictions == null && other.mRestrictions == null && Arrays.equals(mCurrentValues, other.mCurrentValues)) { return true; } if (mCurrentValue == null && other.mCurrentValue == null && mCurrentValue == null && other.mCurrentValue == null && Arrays.equals(mRestrictions, other.mRestrictions)) { return true; } return false; } @Override Loading @@ -397,28 +466,28 @@ public class RestrictionEntry implements Parcelable { result = 31 * result + value.hashCode(); } } } else if (mRestrictions != null) { result = 31 * result + Arrays.hashCode(mRestrictions); } return result; } private String[] readArray(Parcel in) { int count = in.readInt(); String[] values = new String[count]; for (int i = 0; i < count; i++) { values[i] = in.readString(); } return values; } public RestrictionEntry(Parcel in) { mType = in.readInt(); mKey = in.readString(); mTitle = in.readString(); mDescription = in.readString(); mChoiceEntries = readArray(in); mChoiceValues = readArray(in); mChoiceEntries = in.readStringArray(); mChoiceValues = in.readStringArray(); mCurrentValue = in.readString(); mCurrentValues = readArray(in); mCurrentValues = in.readStringArray(); Parcelable[] parcelables = in.readParcelableArray(null); if (parcelables != null) { mRestrictions = new RestrictionEntry[parcelables.length]; for (int i = 0; i < parcelables.length; i++) { mRestrictions[i] = (RestrictionEntry) parcelables[i]; } } } @Override Loading @@ -426,27 +495,17 @@ public class RestrictionEntry implements Parcelable { return 0; } private void writeArray(Parcel dest, String[] values) { if (values == null) { dest.writeInt(0); } else { dest.writeInt(values.length); for (int i = 0; i < values.length; i++) { dest.writeString(values[i]); } } } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); dest.writeString(mKey); dest.writeString(mTitle); dest.writeString(mDescription); writeArray(dest, mChoiceEntries); writeArray(dest, mChoiceValues); dest.writeStringArray(mChoiceEntries); dest.writeStringArray(mChoiceValues); dest.writeString(mCurrentValue); writeArray(dest, mCurrentValues); dest.writeStringArray(mCurrentValues); dest.writeParcelableArray(mRestrictions, 0); } public static final Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() { Loading @@ -461,6 +520,16 @@ public class RestrictionEntry implements Parcelable { @Override public String toString() { return "RestrictionsEntry {type=" + mType + ", key=" + mKey + ", value=" + mCurrentValue + "}"; return "RestrictionEntry{" + "mType=" + mType + ", mKey='" + mKey + '\'' + ", mTitle='" + mTitle + '\'' + ", mDescription='" + mDescription + '\'' + ", mChoiceEntries=" + Arrays.toString(mChoiceEntries) + ", mChoiceValues=" + Arrays.toString(mChoiceValues) + ", mCurrentValue='" + mCurrentValue + '\'' + ", mCurrentValues=" + Arrays.toString(mCurrentValues) + ", mRestrictions=" + Arrays.toString(mRestrictions) + '}'; } }
core/java/android/content/RestrictionsManager.java +112 −18 Original line number Diff line number Diff line Loading @@ -32,12 +32,14 @@ import android.util.Log; import android.util.Xml; import com.android.internal.R; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -71,12 +73,15 @@ import java.util.List; * android:key="string" * android:title="string resource" * android:restrictionType=["bool" | "string" | "integer" * | "choice" | "multi-select" | "hidden"] * | "choice" | "multi-select" | "hidden" * | "bundle" | "bundle_array"] * android:description="string resource" * android:entries="string-array resource" * android:entryValues="string-array resource" * android:defaultValue="reference" * /> * android:defaultValue="reference" > * <restriction ... /> * ... * </restriction> * <restriction ... /> * ... * </restrictions> Loading @@ -97,6 +102,9 @@ import java.util.List; * administrator controlling the values, if the title is not sufficient.</li> * </ul> * <p> * Only restrictions of type {@code bundle} and {@code bundle_array} can have one or multiple nested * restriction elements. * <p> * In your manifest's <code>application</code> section, add the meta-data tag to point to * the restrictions XML file as shown below: * <pre> Loading Loading @@ -537,9 +545,7 @@ public class RestrictionsManager { XmlResourceParser xml = appInfo.loadXmlMetaData(mContext.getPackageManager(), META_DATA_APP_RESTRICTIONS); List<RestrictionEntry> restrictions = loadManifestRestrictions(packageName, xml); return restrictions; return loadManifestRestrictions(packageName, xml); } private List<RestrictionEntry> loadManifestRestrictions(String packageName, Loading @@ -550,25 +556,18 @@ public class RestrictionsManager { } catch (NameNotFoundException nnfe) { return null; } ArrayList<RestrictionEntry> restrictions = new ArrayList<RestrictionEntry>(); ArrayList<RestrictionEntry> restrictions = new ArrayList<>(); RestrictionEntry restriction; try { int tagType = xml.next(); while (tagType != XmlPullParser.END_DOCUMENT) { if (tagType == XmlPullParser.START_TAG) { if (xml.getName().equals(TAG_RESTRICTION)) { AttributeSet attrSet = Xml.asAttributeSet(xml); if (attrSet != null) { TypedArray a = appContext.obtainStyledAttributes(attrSet, com.android.internal.R.styleable.RestrictionEntry); restriction = loadRestriction(appContext, a); restriction = loadRestrictionElement(appContext, xml); if (restriction != null) { restrictions.add(restriction); } } } } tagType = xml.next(); } } catch (XmlPullParserException e) { Loading @@ -582,7 +581,21 @@ public class RestrictionsManager { return restrictions; } private RestrictionEntry loadRestriction(Context appContext, TypedArray a) { private RestrictionEntry loadRestrictionElement(Context appContext, XmlResourceParser xml) throws IOException, XmlPullParserException { if (xml.getName().equals(TAG_RESTRICTION)) { AttributeSet attrSet = Xml.asAttributeSet(xml); if (attrSet != null) { TypedArray a = appContext.obtainStyledAttributes(attrSet, com.android.internal.R.styleable.RestrictionEntry); return loadRestriction(appContext, a, xml); } } return null; } private RestrictionEntry loadRestriction(Context appContext, TypedArray a, XmlResourceParser xml) throws IOException, XmlPullParserException { String key = a.getString(R.styleable.RestrictionEntry_key); int restrictionType = a.getInt( R.styleable.RestrictionEntry_restrictionType, -1); Loading Loading @@ -633,9 +646,90 @@ public class RestrictionsManager { restriction.setSelectedState( a.getBoolean(R.styleable.RestrictionEntry_defaultValue, false)); break; case RestrictionEntry.TYPE_BUNDLE: case RestrictionEntry.TYPE_BUNDLE_ARRAY: final int outerDepth = xml.getDepth(); List<RestrictionEntry> restrictionEntries = new ArrayList<>(); while (XmlUtils.nextElementWithin(xml, outerDepth)) { RestrictionEntry childEntry = loadRestrictionElement(appContext, xml); if (childEntry == null) { Log.w(TAG, "Child entry cannot be loaded for bundle restriction " + key); } else { restrictionEntries.add(childEntry); if (restrictionType == RestrictionEntry.TYPE_BUNDLE_ARRAY && childEntry.getType() != RestrictionEntry.TYPE_BUNDLE) { Log.w(TAG, "bundle_array " + key + " can only contain entries of type bundle"); } } } restriction.setRestrictions(restrictionEntries.toArray(new RestrictionEntry[ restrictionEntries.size()])); break; default: Log.w(TAG, "Unknown restriction type " + restrictionType); } return restriction; } /** * Converts a list of restrictions to the corresponding bundle, using the following mapping: * <table> * <tr><th>RestrictionEntry</th><th>Bundle</th></tr> * <tr><td>{@link RestrictionEntry#TYPE_BOOLEAN}</td><td>{@link Bundle#putBoolean}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_CHOICE}, {@link RestrictionEntry#TYPE_CHOICE}</td> * <td>{@link Bundle#putStringArray}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_INTEGER}</td><td>{@link Bundle#putInt}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_STRING}</td><td>{@link Bundle#putString}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE}</td><td>{@link Bundle#putBundle}</td></tr> * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE_ARRAY}</td> * <td>{@link Bundle#putParcelableArray}</td></tr> * </table> * @param entries list of restrictions */ public static Bundle convertRestrictionsToBundle(List<RestrictionEntry> entries) { final Bundle bundle = new Bundle(); for (RestrictionEntry entry : entries) { addRestrictionToBundle(bundle, entry); } return bundle; } private static Bundle addRestrictionToBundle(Bundle bundle, RestrictionEntry entry) { switch (entry.getType()) { case RestrictionEntry.TYPE_BOOLEAN: bundle.putBoolean(entry.getKey(), entry.getSelectedState()); break; case RestrictionEntry.TYPE_CHOICE: case RestrictionEntry.TYPE_CHOICE_LEVEL: case RestrictionEntry.TYPE_MULTI_SELECT: bundle.putStringArray(entry.getKey(), entry.getAllSelectedStrings()); break; case RestrictionEntry.TYPE_INTEGER: bundle.putInt(entry.getKey(), entry.getIntValue()); break; case RestrictionEntry.TYPE_STRING: case RestrictionEntry.TYPE_NULL: bundle.putString(entry.getKey(), entry.getSelectedString()); break; case RestrictionEntry.TYPE_BUNDLE: RestrictionEntry[] restrictions = entry.getRestrictions(); Bundle childBundle = convertRestrictionsToBundle(Arrays.asList(restrictions)); bundle.putBundle(entry.getKey(), childBundle); break; case RestrictionEntry.TYPE_BUNDLE_ARRAY: restrictions = entry.getRestrictions(); Bundle[] bundleArray = new Bundle[restrictions.length]; for (int i = 0; i < restrictions.length; i++) { bundleArray[i] = addRestrictionToBundle(new Bundle(), restrictions[i]); } bundle.putParcelableArray(entry.getKey(), bundleArray); break; default: throw new IllegalArgumentException( "Unsupported restrictionEntry type: " + entry.getType()); } return bundle; } }
core/res/res/values/attrs.xml +2 −0 Original line number Diff line number Diff line Loading @@ -7759,6 +7759,8 @@ <enum name="multi-select" value="4" /> <enum name="integer" value="5" /> <enum name="string" value="6" /> <enum name="bundle" value="7" /> <enum name="bundle_array" value="8" /> </attr> <attr name="title" /> <attr name="description" /> Loading