Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce50e7af authored by Amith Yamasani's avatar Amith Yamasani Committed by Android (Google) Code Review
Browse files

Merge "App restrictions schema and parser" into lmp-dev

parents 41233447 c8c8425b
Loading
Loading
Loading
Loading
+14 −10
Original line number Diff line number Diff line
@@ -359,7 +359,7 @@ package android {
    field public static final int buttonTint = 16843889; // 0x1010471
    field public static final int buttonTintMode = 16843890; // 0x1010472
    field public static final int cacheColorHint = 16843009; // 0x1010101
    field public static final int calendarTextColor = 16843933; // 0x101049d
    field public static final int calendarTextColor = 16843934; // 0x101049e
    field public static final int calendarViewShown = 16843596; // 0x101034c
    field public static final int calendarViewStyle = 16843613; // 0x101035d
    field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
@@ -448,14 +448,14 @@ package android {
    field public static final int dashWidth = 16843174; // 0x10101a6
    field public static final int data = 16842798; // 0x101002e
    field public static final int datePickerStyle = 16843612; // 0x101035c
    field public static final int dateSelectorBackgroundColor = 16843927; // 0x1010497
    field public static final int dateSelectorDayOfMonthTextAppearance = 16843929; // 0x1010499
    field public static final int dateSelectorDayOfWeekBackgroundColor = 16843925; // 0x1010495
    field public static final int dateSelectorDayOfWeekTextAppearance = 16843926; // 0x1010496
    field public static final int dateSelectorMonthTextAppearance = 16843928; // 0x1010498
    field public static final int dateSelectorYearListItemTextAppearance = 16843931; // 0x101049b
    field public static final int dateSelectorYearListSelectedCircleColor = 16843932; // 0x101049c
    field public static final int dateSelectorYearTextAppearance = 16843930; // 0x101049a
    field public static final int dateSelectorBackgroundColor = 16843928; // 0x1010498
    field public static final int dateSelectorDayOfMonthTextAppearance = 16843930; // 0x101049a
    field public static final int dateSelectorDayOfWeekBackgroundColor = 16843926; // 0x1010496
    field public static final int dateSelectorDayOfWeekTextAppearance = 16843927; // 0x1010497
    field public static final int dateSelectorMonthTextAppearance = 16843929; // 0x1010499
    field public static final int dateSelectorYearListItemTextAppearance = 16843932; // 0x101049c
    field public static final int dateSelectorYearListSelectedCircleColor = 16843933; // 0x101049d
    field public static final int dateSelectorYearTextAppearance = 16843931; // 0x101049b
    field public static final int dateTextAppearance = 16843593; // 0x1010349
    field public static final int debuggable = 16842767; // 0x101000f
    field public static final int defaultValue = 16843245; // 0x10101ed
@@ -1007,6 +1007,7 @@ package android {
    field public static final int restoreAnyVersion = 16843450; // 0x10102ba
    field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
    field public static final int restrictedAccountType = 16843733; // 0x10103d5
    field public static final int restrictionType = 16843925; // 0x1010495
    field public static final int reversible = 16843853; // 0x101044d
    field public static final int right = 16843183; // 0x10101af
    field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
@@ -7934,6 +7935,7 @@ package android.content {
  }
  public class RestrictionEntry implements android.os.Parcelable {
    ctor public RestrictionEntry(int, java.lang.String);
    ctor public RestrictionEntry(java.lang.String, java.lang.String);
    ctor public RestrictionEntry(java.lang.String, boolean);
    ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
@@ -7968,6 +7970,7 @@ package android.content {
    field public static final int TYPE_INTEGER = 5; // 0x5
    field public static final int TYPE_MULTI_SELECT = 4; // 0x4
    field public static final int TYPE_NULL = 0; // 0x0
    field public static final int TYPE_STRING = 6; // 0x6
  }
  public class RestrictionsManager {
@@ -7982,6 +7985,7 @@ package android.content {
    field public static final java.lang.String EXTRA_REQUEST_BUNDLE = "android.content.extra.REQUEST_BUNDLE";
    field public static final java.lang.String EXTRA_REQUEST_TYPE = "android.content.extra.REQUEST_TYPE";
    field public static final java.lang.String EXTRA_RESPONSE_BUNDLE = "android.content.extra.RESPONSE_BUNDLE";
    field public static final java.lang.String META_DATA_APP_RESTRICTIONS = "android.content.APP_RESTRICTIONS";
    field public static final java.lang.String REQUEST_KEY_APPROVE_LABEL = "android.request.approve_label";
    field public static final java.lang.String REQUEST_KEY_DATA = "android.request.data";
    field public static final java.lang.String REQUEST_KEY_DENY_LABEL = "android.request.deny_label";
@@ -7993,7 +7997,7 @@ package android.content {
    field public static final java.lang.String REQUEST_TYPE_APPROVAL = "android.request.type.approval";
    field public static final java.lang.String REQUEST_TYPE_LOCAL_APPROVAL = "android.request.type.local_approval";
    field public static final java.lang.String RESPONSE_KEY_ERROR_CODE = "android.response.errorcode";
    field public static final java.lang.String RESPONSE_KEY_ERROR_MESSAGE = "android.response.errormsg";
    field public static final java.lang.String RESPONSE_KEY_MESSAGE = "android.response.msg";
    field public static final java.lang.String RESPONSE_KEY_RESPONSE_TIMESTAMP = "android.response.timestamp";
    field public static final java.lang.String RESPONSE_KEY_RESULT = "android.response.result";
    field public static final int RESULT_APPROVED = 1; // 0x1
+1 −1
Original line number Diff line number Diff line
@@ -2243,7 +2243,7 @@ public class DevicePolicyManager {
     * application running in the managed profile.
     *
     * <p>The provided {@link Bundle} consists of key-value pairs, where the types of values may be
     * {@link Boolean}, {@link String}, or {@link String}[]. The recommended format for key strings
     * boolean, int, String, or String[]. The recommended format for keys
     * is "com.example.packagename/example-setting" to avoid naming conflicts with library
     * components such as {@link android.webkit.WebView}.
     *
+18 −0
Original line number Diff line number Diff line
@@ -79,6 +79,13 @@ public class RestrictionEntry implements Parcelable {
     */
    public static final int TYPE_INTEGER = 5;

    /**
     * A type of restriction. Use this for storing a string value.
     * @see #setSelectedString
     * @see #getSelectedString
     */
    public static final int TYPE_STRING = 6;

    /** The type of restriction. */
    private int mType;

@@ -106,6 +113,17 @@ public class RestrictionEntry implements Parcelable {
    /* List of selected choices in the multi-select case. */
    private String[] mCurrentValues;

    /**
     * Constructor for specifying the type and key, with no initial value;
     *
     * @param type the restriction type.
     * @param key the unique key for this restriction
     */
    public RestrictionEntry(int type, String key) {
        mType = type;
        mKey = key;
    }

    /**
     * Constructor for {@link #TYPE_CHOICE} type.
     * @param key the unique key for this restriction
+179 −12
Original line number Diff line number Diff line
@@ -17,11 +17,24 @@
package android.content;

import android.app.admin.DevicePolicyManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;

import java.util.Collections;
import com.android.internal.R;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
@@ -49,19 +62,52 @@ import java.util.List;
 * <p>
 * The syntax of the XML format is as follows:
 * <pre>
 * &lt;restrictions&gt;
 * &lt;?xml version="1.0" encoding="utf-8"?&gt;
 * &lt;restrictions xmlns:android="http://schemas.android.com/apk/res/android" &gt;
 *     &lt;restriction
 *         android:key="&lt;key&gt;"
 *         android:restrictionType="boolean|string|integer|multi-select|null"
 *         ... /&gt;
 *         android:key="string"
 *         android:title="string resource"
 *         android:restrictionType=["bool" | "string" | "integer"
 *                                         | "choice" | "multi-select" | "hidden"]
 *         android:description="string resource"
 *         android:entries="string-array resource"
 *         android:entryValues="string-array resource"
 *         android:defaultValue="reference"
 *         /&gt;
 *     &lt;restriction ... /&gt;
 *     ...
 * &lt;/restrictions&gt;
 * </pre>
 * <p>
 * The attributes for each restriction depend on the restriction type.
 * <p>
 * <ul>
 * <li><code>key</code>, <code>title</code> and <code>restrictionType</code> are mandatory.</li>
 * <li><code>entries</code> and <code>entryValues</code> are required if <code>restrictionType
 * </code> is <code>choice</code> or <code>multi-select</code>.</li>
 * <li><code>defaultValue</code> is optional and its type depends on the
 * <code>restrictionType</code></li>
 * <li><code>hidden</code> type must have a <code>defaultValue</code> and will
 * not be shown to the administrator. It can be used to pass along data that cannot be modified,
 * such as a version code.</li>
 * <li><code>description</code> is meant to describe the restriction in more detail to the
 * administrator controlling the values, if the title is not sufficient.</li>
 * </ul>
 * <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>
 * &lt;application ... &gt;
 *     &lt;meta-data android:name="android.content.APP_RESTRICTIONS"
 *                   android:resource="@xml/app_restrictions" /&gt;
 *     ...
 * &lt;/application&gt;
 * </pre>
 *
 * @see RestrictionEntry
 * @see AbstractRestrictionsProvider
 * @see DevicePolicyManager#setRestrictionsProvider(ComponentName, ComponentName)
 * @see DevicePolicyManager#setApplicationRestrictions(ComponentName, String, Bundle)
 */
public class RestrictionsManager {

@@ -231,8 +277,9 @@ public class RestrictionsManager {
    public static final String REQUEST_KEY_NEW_REQUEST = "android.request.new_request";

    /**
     * Key for the response in the response bundle sent to the application, for a permission
     * request.
     * Key for the response result in the response bundle sent to the application, for a permission
     * request. It indicates the status of the request. In some cases an additional message might
     * be available in {@link #RESPONSE_KEY_MESSAGE}, to be displayed to the user.
     * <p>
     * Type: int
     * <p>
@@ -267,7 +314,7 @@ public class RestrictionsManager {
     * Response result value indicating an error condition. Additional error code might be available
     * in the response bundle, for the key {@link #RESPONSE_KEY_ERROR_CODE}. There might also be
     * an associated error message in the response bundle, for the key
     * {@link #RESPONSE_KEY_ERROR_MESSAGE}.
     * {@link #RESPONSE_KEY_MESSAGE}.
     */
    public static final int RESULT_ERROR = 5;

@@ -303,11 +350,11 @@ public class RestrictionsManager {
    public static final String RESPONSE_KEY_ERROR_CODE = "android.response.errorcode";

    /**
     * Key for the optional error message in the response bundle sent to the application.
     * Key for the optional message in the response bundle sent to the application.
     * <p>
     * Type: String
     */
    public static final String RESPONSE_KEY_ERROR_MESSAGE = "android.response.errormsg";
    public static final String RESPONSE_KEY_MESSAGE = "android.response.msg";

    /**
     * Key for the optional timestamp of when the administrator responded to the permission
@@ -317,6 +364,15 @@ public class RestrictionsManager {
     */
    public static final String RESPONSE_KEY_RESPONSE_TIMESTAMP = "android.response.timestamp";

    /**
     * Name of the meta-data entry in the manifest that points to the XML file containing the
     * application's available restrictions.
     * @see #getManifestRestrictions(String)
     */
    public static final String META_DATA_APP_RESTRICTIONS = "android.content.APP_RESTRICTIONS";

    private static final String TAG_RESTRICTION = "restriction";

    private final Context mContext;
    private final IRestrictionsManager mService;

@@ -436,7 +492,118 @@ public class RestrictionsManager {
     * in the manifest, or null if none was specified.
     */
    public List<RestrictionEntry> getManifestRestrictions(String packageName) {
        // TODO:
        ApplicationInfo appInfo = null;
        try {
            appInfo = mContext.getPackageManager().getApplicationInfo(packageName,
                    PackageManager.GET_META_DATA);
        } catch (NameNotFoundException pnfe) {
            throw new IllegalArgumentException("No such package " + packageName);
        }
        if (appInfo == null || !appInfo.metaData.containsKey(META_DATA_APP_RESTRICTIONS)) {
            return null;
        }

        XmlResourceParser xml =
                appInfo.loadXmlMetaData(mContext.getPackageManager(), META_DATA_APP_RESTRICTIONS);
        List<RestrictionEntry> restrictions = loadManifestRestrictions(packageName, xml);

        return restrictions;
    }

    private List<RestrictionEntry> loadManifestRestrictions(String packageName,
            XmlResourceParser xml) {
        Context appContext;
        try {
            appContext = mContext.createPackageContext(packageName, 0 /* flags */);
        } catch (NameNotFoundException nnfe) {
            return null;
        }
        ArrayList<RestrictionEntry> restrictions = new ArrayList<RestrictionEntry>();
        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);
                            if (restriction != null) {
                                restrictions.add(restriction);
                            }
                        }
                    }
                }
                tagType = xml.next();
            }
        } catch (XmlPullParserException e) {
            Log.w(TAG, "Reading restriction metadata for " + packageName, e);
            return null;
        } catch (IOException e) {
            Log.w(TAG, "Reading restriction metadata for " + packageName, e);
            return null;
        }

        return restrictions;
    }

    private RestrictionEntry loadRestriction(Context appContext, TypedArray a) {
        String key = a.getString(R.styleable.RestrictionEntry_key);
        int restrictionType = a.getInt(
                R.styleable.RestrictionEntry_restrictionType, -1);
        String title = a.getString(R.styleable.RestrictionEntry_title);
        String description = a.getString(R.styleable.RestrictionEntry_description);
        int entries = a.getResourceId(R.styleable.RestrictionEntry_entries, 0);
        int entryValues = a.getResourceId(R.styleable.RestrictionEntry_entryValues, 0);

        if (restrictionType == -1) {
            Log.w(TAG, "restrictionType cannot be omitted");
            return null;
        }

        if (key == null) {
            Log.w(TAG, "key cannot be omitted");
            return null;
        }

        RestrictionEntry restriction = new RestrictionEntry(restrictionType, key);
        restriction.setTitle(title);
        restriction.setDescription(description);
        if (entries != 0) {
            restriction.setChoiceEntries(appContext, entries);
        }
        if (entryValues != 0) {
            restriction.setChoiceValues(appContext, entryValues);
        }
        // Extract the default value based on the type
        switch (restrictionType) {
            case RestrictionEntry.TYPE_NULL: // hidden
            case RestrictionEntry.TYPE_STRING:
            case RestrictionEntry.TYPE_CHOICE:
                restriction.setSelectedString(
                        a.getString(R.styleable.RestrictionEntry_defaultValue));
                break;
            case RestrictionEntry.TYPE_INTEGER:
                restriction.setIntValue(
                        a.getInt(R.styleable.RestrictionEntry_defaultValue, 0));
                break;
            case RestrictionEntry.TYPE_MULTI_SELECT:
                int resId = a.getResourceId(R.styleable.RestrictionEntry_defaultValue, 0);
                if (resId != 0) {
                    restriction.setAllSelectedStrings(
                            appContext.getResources().getStringArray(resId));
                }
                break;
            case RestrictionEntry.TYPE_BOOLEAN:
                restriction.setSelectedState(
                        a.getBoolean(R.styleable.RestrictionEntry_defaultValue, false));
                break;
            default:
                Log.w(TAG, "Unknown restriction type " + restrictionType);
        }
        return restriction;
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -7218,4 +7218,21 @@
        <attr name="ambientShadowAlpha" format="float" />
        <attr name="spotShadowAlpha" format="float" />
    </declare-styleable>

    <declare-styleable name="RestrictionEntry">
        <attr name="key" />
        <attr name="restrictionType">
            <enum name="hidden" value="0" />
            <enum name="bool" value="1" />
            <enum name="choice" value="2" />
            <enum name="multi-select" value="4" />
            <enum name="integer" value="5" />
            <enum name="string" value="6" />
        </attr>
        <attr name="title" />
        <attr name="description" />
        <attr name="defaultValue" />
        <attr name="entries" />
        <attr name="entryValues" />
    </declare-styleable>
</resources>
Loading