Home | History | Annotate | Download | only in admin
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.app.admin;
     18 
     19 import org.xmlpull.v1.XmlPullParser;
     20 import org.xmlpull.v1.XmlPullParserException;
     21 import org.xmlpull.v1.XmlSerializer;
     22 
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.pm.ActivityInfo;
     26 import android.content.pm.ApplicationInfo;
     27 import android.content.pm.PackageManager;
     28 import android.content.pm.ResolveInfo;
     29 import android.content.pm.PackageManager.NameNotFoundException;
     30 import android.content.res.Resources;
     31 import android.content.res.TypedArray;
     32 import android.content.res.XmlResourceParser;
     33 import android.content.res.Resources.NotFoundException;
     34 import android.graphics.drawable.Drawable;
     35 import android.os.Parcel;
     36 import android.os.Parcelable;
     37 import android.util.AttributeSet;
     38 import android.util.Log;
     39 import android.util.Printer;
     40 import android.util.SparseArray;
     41 import android.util.Xml;
     42 
     43 import java.io.IOException;
     44 import java.util.ArrayList;
     45 import java.util.HashMap;
     46 
     47 /**
     48  * This class is used to specify meta information of a device administrator
     49  * component.
     50  */
     51 public final class DeviceAdminInfo implements Parcelable {
     52     static final String TAG = "DeviceAdminInfo";
     53 
     54     /**
     55      * A type of policy that this device admin can use: limit the passwords
     56      * that the user can select, via {@link DevicePolicyManager#setPasswordQuality}
     57      * and {@link DevicePolicyManager#setPasswordMinimumLength}.
     58      *
     59      * <p>To control this policy, the device admin must have a "limit-password"
     60      * tag in the "uses-policies" section of its meta-data.
     61      */
     62     public static final int USES_POLICY_LIMIT_PASSWORD = 0;
     63 
     64     /**
     65      * A type of policy that this device admin can use: able to watch login
     66      * attempts from the user, via {@link DeviceAdminReceiver#ACTION_PASSWORD_FAILED},
     67      * {@link DeviceAdminReceiver#ACTION_PASSWORD_SUCCEEDED}, and
     68      * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts}.
     69      *
     70      * <p>To control this policy, the device admin must have a "watch-login"
     71      * tag in the "uses-policies" section of its meta-data.
     72      */
     73     public static final int USES_POLICY_WATCH_LOGIN = 1;
     74 
     75     /**
     76      * A type of policy that this device admin can use: able to reset the
     77      * user's password via
     78      * {@link DevicePolicyManager#resetPassword}.
     79      *
     80      * <p>To control this policy, the device admin must have a "reset-password"
     81      * tag in the "uses-policies" section of its meta-data.
     82      */
     83     public static final int USES_POLICY_RESET_PASSWORD = 2;
     84 
     85     /**
     86      * A type of policy that this device admin can use: able to force the device
     87      * to lock via{@link DevicePolicyManager#lockNow} or limit the
     88      * maximum lock timeout for the device via
     89      * {@link DevicePolicyManager#setMaximumTimeToLock}.
     90      *
     91      * <p>To control this policy, the device admin must have a "force-lock"
     92      * tag in the "uses-policies" section of its meta-data.
     93      */
     94     public static final int USES_POLICY_FORCE_LOCK = 3;
     95 
     96     /**
     97      * A type of policy that this device admin can use: able to factory
     98      * reset the device, erasing all of the user's data, via
     99      * {@link DevicePolicyManager#wipeData}.
    100      *
    101      * <p>To control this policy, the device admin must have a "wipe-data"
    102      * tag in the "uses-policies" section of its meta-data.
    103      */
    104     public static final int USES_POLICY_WIPE_DATA = 4;
    105 
    106     /** @hide */
    107     public static class PolicyInfo {
    108         public final int ident;
    109         final public String tag;
    110         final public int label;
    111         final public int description;
    112 
    113         public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
    114             ident = identIn;
    115             tag = tagIn;
    116             label = labelIn;
    117             description = descriptionIn;
    118         }
    119     }
    120 
    121     static ArrayList<PolicyInfo> sPoliciesDisplayOrder = new ArrayList<PolicyInfo>();
    122     static HashMap<String, Integer> sKnownPolicies = new HashMap<String, Integer>();
    123     static SparseArray<PolicyInfo> sRevKnownPolicies = new SparseArray<PolicyInfo>();
    124 
    125     static {
    126         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
    127                 com.android.internal.R.string.policylab_wipeData,
    128                 com.android.internal.R.string.policydesc_wipeData));
    129         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
    130                 com.android.internal.R.string.policylab_resetPassword,
    131                 com.android.internal.R.string.policydesc_resetPassword));
    132         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_LIMIT_PASSWORD, "limit-password",
    133                 com.android.internal.R.string.policylab_limitPassword,
    134                 com.android.internal.R.string.policydesc_limitPassword));
    135         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
    136                 com.android.internal.R.string.policylab_watchLogin,
    137                 com.android.internal.R.string.policydesc_watchLogin));
    138         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
    139                 com.android.internal.R.string.policylab_forceLock,
    140                 com.android.internal.R.string.policydesc_forceLock));
    141 
    142         for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
    143             PolicyInfo pi = sPoliciesDisplayOrder.get(i);
    144             sRevKnownPolicies.put(pi.ident, pi);
    145             sKnownPolicies.put(pi.tag, pi.ident);
    146         }
    147     }
    148 
    149     /**
    150      * The BroadcastReceiver that implements this device admin component.
    151      */
    152     final ResolveInfo mReceiver;
    153 
    154     /**
    155      * Whether this should be visible to the user.
    156      */
    157     boolean mVisible;
    158 
    159     /**
    160      * The policies this administrator needs access to.
    161      */
    162     int mUsesPolicies;
    163 
    164     /**
    165      * Constructor.
    166      *
    167      * @param context The Context in which we are parsing the device admin.
    168      * @param receiver The ResolveInfo returned from the package manager about
    169      * this device admin's component.
    170      */
    171     public DeviceAdminInfo(Context context, ResolveInfo receiver)
    172             throws XmlPullParserException, IOException {
    173         mReceiver = receiver;
    174         ActivityInfo ai = receiver.activityInfo;
    175 
    176         PackageManager pm = context.getPackageManager();
    177 
    178         XmlResourceParser parser = null;
    179         try {
    180             parser = ai.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
    181             if (parser == null) {
    182                 throw new XmlPullParserException("No "
    183                         + DeviceAdminReceiver.DEVICE_ADMIN_META_DATA + " meta-data");
    184             }
    185 
    186             Resources res = pm.getResourcesForApplication(ai.applicationInfo);
    187 
    188             AttributeSet attrs = Xml.asAttributeSet(parser);
    189 
    190             int type;
    191             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    192                     && type != XmlPullParser.START_TAG) {
    193             }
    194 
    195             String nodeName = parser.getName();
    196             if (!"device-admin".equals(nodeName)) {
    197                 throw new XmlPullParserException(
    198                         "Meta-data does not start with device-admin tag");
    199             }
    200 
    201             TypedArray sa = res.obtainAttributes(attrs,
    202                     com.android.internal.R.styleable.DeviceAdmin);
    203 
    204             mVisible = sa.getBoolean(
    205                     com.android.internal.R.styleable.DeviceAdmin_visible, true);
    206 
    207             sa.recycle();
    208 
    209             int outerDepth = parser.getDepth();
    210             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    211                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    212                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    213                     continue;
    214                 }
    215                 String tagName = parser.getName();
    216                 if (tagName.equals("uses-policies")) {
    217                     int innerDepth = parser.getDepth();
    218                     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    219                            && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
    220                         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    221                             continue;
    222                         }
    223                         String policyName = parser.getName();
    224                         Integer val = sKnownPolicies.get(policyName);
    225                         if (val != null) {
    226                             mUsesPolicies |= 1 << val.intValue();
    227                         } else {
    228                             Log.w(TAG, "Unknown tag under uses-policies of "
    229                                     + getComponent() + ": " + policyName);
    230                         }
    231                     }
    232                 }
    233             }
    234         } catch (NameNotFoundException e) {
    235             throw new XmlPullParserException(
    236                     "Unable to create context for: " + ai.packageName);
    237         } finally {
    238             if (parser != null) parser.close();
    239         }
    240     }
    241 
    242     DeviceAdminInfo(Parcel source) {
    243         mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
    244         mUsesPolicies = source.readInt();
    245     }
    246 
    247     /**
    248      * Return the .apk package that implements this device admin.
    249      */
    250     public String getPackageName() {
    251         return mReceiver.activityInfo.packageName;
    252     }
    253 
    254     /**
    255      * Return the class name of the receiver component that implements
    256      * this device admin.
    257      */
    258     public String getReceiverName() {
    259         return mReceiver.activityInfo.name;
    260     }
    261 
    262     /**
    263      * Return the raw information about the receiver implementing this
    264      * device admin.  Do not modify the returned object.
    265      */
    266     public ActivityInfo getActivityInfo() {
    267         return mReceiver.activityInfo;
    268     }
    269 
    270     /**
    271      * Return the component of the receiver that implements this device admin.
    272      */
    273     public ComponentName getComponent() {
    274         return new ComponentName(mReceiver.activityInfo.packageName,
    275                 mReceiver.activityInfo.name);
    276     }
    277 
    278     /**
    279      * Load the user-displayed label for this device admin.
    280      *
    281      * @param pm Supply a PackageManager used to load the device admin's
    282      * resources.
    283      */
    284     public CharSequence loadLabel(PackageManager pm) {
    285         return mReceiver.loadLabel(pm);
    286     }
    287 
    288     /**
    289      * Load user-visible description associated with this device admin.
    290      *
    291      * @param pm Supply a PackageManager used to load the device admin's
    292      * resources.
    293      */
    294     public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
    295         if (mReceiver.activityInfo.descriptionRes != 0) {
    296             String packageName = mReceiver.resolvePackageName;
    297             ApplicationInfo applicationInfo = null;
    298             if (packageName == null) {
    299                 packageName = mReceiver.activityInfo.packageName;
    300                 applicationInfo = mReceiver.activityInfo.applicationInfo;
    301             }
    302             return pm.getText(packageName,
    303                     mReceiver.activityInfo.descriptionRes, applicationInfo);
    304         }
    305         throw new NotFoundException();
    306     }
    307 
    308     /**
    309      * Load the user-displayed icon for this device admin.
    310      *
    311      * @param pm Supply a PackageManager used to load the device admin's
    312      * resources.
    313      */
    314     public Drawable loadIcon(PackageManager pm) {
    315         return mReceiver.loadIcon(pm);
    316     }
    317 
    318     /**
    319      * Returns whether this device admin would like to be visible to the
    320      * user, even when it is not enabled.
    321      */
    322     public boolean isVisible() {
    323         return mVisible;
    324     }
    325 
    326     /**
    327      * Return true if the device admin has requested that it be able to use
    328      * the given policy control.  The possible policy identifier inputs are:
    329      * {@link #USES_POLICY_LIMIT_PASSWORD}, {@link #USES_POLICY_WATCH_LOGIN},
    330      * {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_FORCE_LOCK},
    331      * {@link #USES_POLICY_WIPE_DATA}.
    332      */
    333     public boolean usesPolicy(int policyIdent) {
    334         return (mUsesPolicies & (1<<policyIdent)) != 0;
    335     }
    336 
    337     /**
    338      * Return the XML tag name for the given policy identifier.  Valid identifiers
    339      * are as per {@link #usesPolicy(int)}.  If the given identifier is not
    340      * known, null is returned.
    341      */
    342     public String getTagForPolicy(int policyIdent) {
    343         return sRevKnownPolicies.get(policyIdent).tag;
    344     }
    345 
    346     /** @hide */
    347     public ArrayList<PolicyInfo> getUsedPolicies() {
    348         ArrayList<PolicyInfo> res = new ArrayList<PolicyInfo>();
    349         for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
    350             PolicyInfo pi = sPoliciesDisplayOrder.get(i);
    351             if (usesPolicy(pi.ident)) {
    352                 res.add(pi);
    353             }
    354         }
    355         return res;
    356     }
    357 
    358     /** @hide */
    359     public void writePoliciesToXml(XmlSerializer out)
    360             throws IllegalArgumentException, IllegalStateException, IOException {
    361         out.attribute(null, "flags", Integer.toString(mUsesPolicies));
    362     }
    363 
    364     /** @hide */
    365     public void readPoliciesFromXml(XmlPullParser parser)
    366             throws XmlPullParserException, IOException {
    367         mUsesPolicies = Integer.parseInt(
    368                 parser.getAttributeValue(null, "flags"));
    369     }
    370 
    371     public void dump(Printer pw, String prefix) {
    372         pw.println(prefix + "Receiver:");
    373         mReceiver.dump(pw, prefix + "  ");
    374     }
    375 
    376     @Override
    377     public String toString() {
    378         return "DeviceAdminInfo{" + mReceiver.activityInfo.name + "}";
    379     }
    380 
    381     /**
    382      * Used to package this object into a {@link Parcel}.
    383      *
    384      * @param dest The {@link Parcel} to be written.
    385      * @param flags The flags used for parceling.
    386      */
    387     public void writeToParcel(Parcel dest, int flags) {
    388         mReceiver.writeToParcel(dest, flags);
    389         dest.writeInt(mUsesPolicies);
    390     }
    391 
    392     /**
    393      * Used to make this class parcelable.
    394      */
    395     public static final Parcelable.Creator<DeviceAdminInfo> CREATOR =
    396             new Parcelable.Creator<DeviceAdminInfo>() {
    397         public DeviceAdminInfo createFromParcel(Parcel source) {
    398             return new DeviceAdminInfo(source);
    399         }
    400 
    401         public DeviceAdminInfo[] newArray(int size) {
    402             return new DeviceAdminInfo[size];
    403         }
    404     };
    405 
    406     public int describeContents() {
    407         return 0;
    408     }
    409 }
    410