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 android.annotation.NonNull;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.pm.ActivityInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PackageManager.NameNotFoundException;
26 import android.content.pm.ResolveInfo;
27 import android.content.res.Resources;
28 import android.content.res.Resources.NotFoundException;
29 import android.content.res.TypedArray;
30 import android.content.res.XmlResourceParser;
31 import android.graphics.drawable.Drawable;
32 import android.os.Build;
33 import android.os.Parcel;
34 import android.os.Parcelable;
35 import android.os.PersistableBundle;
36 import android.util.AttributeSet;
37 import android.util.Log;
38 import android.util.Printer;
39 import android.util.SparseArray;
40 import android.util.Xml;
41 
42 import org.xmlpull.v1.XmlPullParser;
43 import org.xmlpull.v1.XmlPullParserException;
44 import org.xmlpull.v1.XmlSerializer;
45 
46 import java.io.IOException;
47 import java.util.ArrayList;
48 import java.util.HashMap;
49 
50 /**
51  * This class is used to specify meta information of a device administrator
52  * component.
53  */
54 public final class DeviceAdminInfo implements Parcelable {
55     static final String TAG = "DeviceAdminInfo";
56 
57     /**
58      * A type of policy that this device admin can use: profile owner on an organization-owned
59      * device.
60      *
61      * @hide
62      */
63     public static final int USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER = -3;
64 
65     /**
66      * A type of policy that this device admin can use: device owner meta-policy
67      * for an admin that is designated as owner of the device.
68      *
69      * @hide
70      */
71     public static final int USES_POLICY_DEVICE_OWNER = -2;
72 
73     /**
74      * A type of policy that this device admin can use: profile owner meta-policy
75      * for admins that have been installed as owner of some user profile.
76      *
77      * @hide
78      */
79     public static final int USES_POLICY_PROFILE_OWNER = -1;
80 
81     /**
82      * A type of policy that this device admin can use: limit the passwords
83      * that the user can select, via {@link DevicePolicyManager#setPasswordQuality}
84      * and {@link DevicePolicyManager#setPasswordMinimumLength}.
85      *
86      * <p>To control this policy, the device admin must be a device owner or profile owner,
87      * and must have a "limit-password" tag in the "uses-policies" section of its meta-data.
88      * If used by a device owner, the policy only affects the primary user and its profiles,
89      * but not any secondary users on the device.
90      */
91     public static final int USES_POLICY_LIMIT_PASSWORD = 0;
92 
93     /**
94      * A type of policy that this device admin can use: able to watch login
95      * attempts from the user, via {@link DeviceAdminReceiver#ACTION_PASSWORD_FAILED},
96      * {@link DeviceAdminReceiver#ACTION_PASSWORD_SUCCEEDED}, and
97      * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts}.
98      *
99      * <p>To control this policy, the device admin must have a "watch-login"
100      * tag in the "uses-policies" section of its meta-data.
101      */
102     public static final int USES_POLICY_WATCH_LOGIN = 1;
103 
104     /**
105      * A type of policy that this device admin can use: able to reset the
106      * user's password via
107      * {@link DevicePolicyManager#resetPassword}.
108      *
109      * <p>To control this policy, the device admin must have a "reset-password"
110      * tag in the "uses-policies" section of its meta-data.
111      */
112     public static final int USES_POLICY_RESET_PASSWORD = 2;
113 
114     /**
115      * A type of policy that this device admin can use: able to force the device
116      * to lock via{@link DevicePolicyManager#lockNow} or limit the
117      * maximum lock timeout for the device via
118      * {@link DevicePolicyManager#setMaximumTimeToLock}.
119      *
120      * <p>To control this policy, the device admin must have a "force-lock"
121      * tag in the "uses-policies" section of its meta-data.
122      */
123     public static final int USES_POLICY_FORCE_LOCK = 3;
124 
125     /**
126      * A type of policy that this device admin can use: able to factory
127      * reset the device, erasing all of the user's data, via
128      * {@link DevicePolicyManager#wipeData}.
129      *
130      * <p>To control this policy, the device admin must have a "wipe-data"
131      * tag in the "uses-policies" section of its meta-data.
132      */
133     public static final int USES_POLICY_WIPE_DATA = 4;
134 
135     /**
136      * A type of policy that this device admin can use: able to specify the
137      * device Global Proxy, via {@link DevicePolicyManager#setGlobalProxy}.
138      *
139      * <p>To control this policy, the device admin must have a "set-global-proxy"
140      * tag in the "uses-policies" section of its meta-data.
141      * @hide
142      */
143     public static final int USES_POLICY_SETS_GLOBAL_PROXY = 5;
144 
145     /**
146      * A type of policy that this device admin can use: force the user to
147      * change their password after an administrator-defined time limit.
148      *
149      * <p>To control this policy, the device admin must be a device owner or profile owner,
150      * and must have an "expire-password" tag in the "uses-policies" section of its meta-data.
151      * If used by a device owner, the policy only affects the primary user and its profiles,
152      * but not any secondary users on the device.
153      */
154     public static final int USES_POLICY_EXPIRE_PASSWORD = 6;
155 
156     /**
157      * A type of policy that this device admin can use: require encryption of stored data.
158      *
159      * <p>To control this policy, the device admin must have a "encrypted-storage"
160      * tag in the "uses-policies" section of its meta-data.
161      */
162     public static final int USES_ENCRYPTED_STORAGE = 7;
163 
164     /**
165      * A type of policy that this device admin can use: disables use of all device cameras.
166      *
167      * <p>To control this policy, the device admin must be a device owner or profile owner,
168      * and must have a "disable-camera" tag in the "uses-policies" section of its meta-data.
169      * If used by a device owner, the policy affects all users on the device.
170      */
171     public static final int USES_POLICY_DISABLE_CAMERA = 8;
172 
173     /**
174      * A type of policy that this device admin can use: disables use of keyguard features.
175      *
176      * <p>To control this policy, the device admin must be a device owner or profile owner,
177      * and must have a "disable-keyguard-features" tag in the "uses-policies" section of its
178      * meta-data.  If used by a device owner, the policy only affects the primary user and
179      * its profiles, but not any secondary users on the device.
180      */
181     public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9;
182 
183     /** @hide */
184     public static class PolicyInfo {
185         public final int ident;
186         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
187         public final String tag;
188         public final int label;
189         public final int description;
190         public final int labelForSecondaryUsers;
191         public final int descriptionForSecondaryUsers;
192 
PolicyInfo(int ident, String tag, int label, int description)193         public PolicyInfo(int ident, String tag, int label, int description) {
194             this(ident, tag, label, description, label, description);
195         }
196 
PolicyInfo(int ident, String tag, int label, int description, int labelForSecondaryUsers, int descriptionForSecondaryUsers)197         public PolicyInfo(int ident, String tag, int label, int description,
198                 int labelForSecondaryUsers, int descriptionForSecondaryUsers) {
199             this.ident = ident;
200             this.tag = tag;
201             this.label = label;
202             this.description = description;
203             this.labelForSecondaryUsers = labelForSecondaryUsers;
204             this.descriptionForSecondaryUsers = descriptionForSecondaryUsers;
205         }
206     }
207 
208     static ArrayList<PolicyInfo> sPoliciesDisplayOrder = new ArrayList<PolicyInfo>();
209     static HashMap<String, Integer> sKnownPolicies = new HashMap<String, Integer>();
210     static SparseArray<PolicyInfo> sRevKnownPolicies = new SparseArray<PolicyInfo>();
211 
212     static {
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data", com.android.internal.R.string.policylab_wipeData, com.android.internal.R.string.policydesc_wipeData, com.android.internal.R.string.policylab_wipeData_secondaryUser, com.android.internal.R.string.policydesc_wipeData_secondaryUser ))213         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
214                 com.android.internal.R.string.policylab_wipeData,
215                 com.android.internal.R.string.policydesc_wipeData,
216                 com.android.internal.R.string.policylab_wipeData_secondaryUser,
217                 com.android.internal.R.string.policydesc_wipeData_secondaryUser
218                 ));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password", com.android.internal.R.string.policylab_resetPassword, com.android.internal.R.string.policydesc_resetPassword))219         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
220                 com.android.internal.R.string.policylab_resetPassword,
221                 com.android.internal.R.string.policydesc_resetPassword));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_LIMIT_PASSWORD, "limit-password", com.android.internal.R.string.policylab_limitPassword, com.android.internal.R.string.policydesc_limitPassword))222         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_LIMIT_PASSWORD, "limit-password",
223                 com.android.internal.R.string.policylab_limitPassword,
224                 com.android.internal.R.string.policydesc_limitPassword));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login", com.android.internal.R.string.policylab_watchLogin, com.android.internal.R.string.policydesc_watchLogin, com.android.internal.R.string.policylab_watchLogin, com.android.internal.R.string.policydesc_watchLogin_secondaryUser ))225         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
226                 com.android.internal.R.string.policylab_watchLogin,
227                 com.android.internal.R.string.policydesc_watchLogin,
228                 com.android.internal.R.string.policylab_watchLogin,
229                 com.android.internal.R.string.policydesc_watchLogin_secondaryUser
230         ));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock", com.android.internal.R.string.policylab_forceLock, com.android.internal.R.string.policydesc_forceLock))231         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
232                 com.android.internal.R.string.policylab_forceLock,
233                 com.android.internal.R.string.policydesc_forceLock));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_SETS_GLOBAL_PROXY, "set-global-proxy", com.android.internal.R.string.policylab_setGlobalProxy, com.android.internal.R.string.policydesc_setGlobalProxy))234         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_SETS_GLOBAL_PROXY, "set-global-proxy",
235                 com.android.internal.R.string.policylab_setGlobalProxy,
236                 com.android.internal.R.string.policydesc_setGlobalProxy));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_EXPIRE_PASSWORD, "expire-password", com.android.internal.R.string.policylab_expirePassword, com.android.internal.R.string.policydesc_expirePassword))237         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_EXPIRE_PASSWORD, "expire-password",
238                 com.android.internal.R.string.policylab_expirePassword,
239                 com.android.internal.R.string.policydesc_expirePassword));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_ENCRYPTED_STORAGE, "encrypted-storage", com.android.internal.R.string.policylab_encryptedStorage, com.android.internal.R.string.policydesc_encryptedStorage))240         sPoliciesDisplayOrder.add(new PolicyInfo(USES_ENCRYPTED_STORAGE, "encrypted-storage",
241                 com.android.internal.R.string.policylab_encryptedStorage,
242                 com.android.internal.R.string.policydesc_encryptedStorage));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_DISABLE_CAMERA, "disable-camera", com.android.internal.R.string.policylab_disableCamera, com.android.internal.R.string.policydesc_disableCamera))243         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_DISABLE_CAMERA, "disable-camera",
244                 com.android.internal.R.string.policylab_disableCamera,
245                 com.android.internal.R.string.policydesc_disableCamera));
sPoliciesDisplayOrder.add(new PolicyInfo( USES_POLICY_DISABLE_KEYGUARD_FEATURES, "disable-keyguard-features", com.android.internal.R.string.policylab_disableKeyguardFeatures, com.android.internal.R.string.policydesc_disableKeyguardFeatures))246         sPoliciesDisplayOrder.add(new PolicyInfo(
247                 USES_POLICY_DISABLE_KEYGUARD_FEATURES, "disable-keyguard-features",
248                 com.android.internal.R.string.policylab_disableKeyguardFeatures,
249                 com.android.internal.R.string.policydesc_disableKeyguardFeatures));
250 
251         for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
252             PolicyInfo pi = sPoliciesDisplayOrder.get(i);
sRevKnownPolicies.put(pi.ident, pi)253             sRevKnownPolicies.put(pi.ident, pi);
sKnownPolicies.put(pi.tag, pi.ident)254             sKnownPolicies.put(pi.tag, pi.ident);
255         }
256     }
257 
258     /**
259      * The BroadcastReceiver that implements this device admin component.
260      */
261     final ActivityInfo mActivityInfo;
262 
263     /**
264      * Whether this should be visible to the user.
265      */
266     boolean mVisible;
267 
268     /**
269      * The policies this administrator needs access to.
270      */
271     int mUsesPolicies;
272 
273     /**
274      * Whether this administrator can be a target in an ownership transfer.
275      *
276      * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
277      */
278     boolean mSupportsTransferOwnership;
279 
280     /**
281      * Constructor.
282      *
283      * @param context The Context in which we are parsing the device admin.
284      * @param resolveInfo The ResolveInfo returned from the package manager about
285      * this device admin's component.
286      */
DeviceAdminInfo(Context context, ResolveInfo resolveInfo)287     public DeviceAdminInfo(Context context, ResolveInfo resolveInfo)
288             throws XmlPullParserException, IOException {
289         this(context, resolveInfo.activityInfo);
290     }
291     /**
292      * Constructor.
293      *
294      * @param context The Context in which we are parsing the device admin.
295      * @param activityInfo The ActivityInfo returned from the package manager about
296      * this device admin's component.
297      *
298      * @hide
299      */
DeviceAdminInfo(Context context, ActivityInfo activityInfo)300     public DeviceAdminInfo(Context context, ActivityInfo activityInfo)
301             throws XmlPullParserException, IOException {
302         mActivityInfo = activityInfo;
303 
304         PackageManager pm = context.getPackageManager();
305 
306         XmlResourceParser parser = null;
307         try {
308             parser = mActivityInfo.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
309             if (parser == null) {
310                 throw new XmlPullParserException("No "
311                         + DeviceAdminReceiver.DEVICE_ADMIN_META_DATA + " meta-data");
312             }
313 
314             Resources res = pm.getResourcesForApplication(mActivityInfo.applicationInfo);
315 
316             AttributeSet attrs = Xml.asAttributeSet(parser);
317 
318             int type;
319             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
320                     && type != XmlPullParser.START_TAG) {
321             }
322 
323             String nodeName = parser.getName();
324             if (!"device-admin".equals(nodeName)) {
325                 throw new XmlPullParserException(
326                         "Meta-data does not start with device-admin tag");
327             }
328 
329             TypedArray sa = res.obtainAttributes(attrs,
330                     com.android.internal.R.styleable.DeviceAdmin);
331 
332             mVisible = sa.getBoolean(
333                     com.android.internal.R.styleable.DeviceAdmin_visible, true);
334 
335             sa.recycle();
336 
337             int outerDepth = parser.getDepth();
338             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
339                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
340                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
341                     continue;
342                 }
343                 String tagName = parser.getName();
344                 if (tagName.equals("uses-policies")) {
345                     int innerDepth = parser.getDepth();
346                     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
347                            && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
348                         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
349                             continue;
350                         }
351                         String policyName = parser.getName();
352                         Integer val = sKnownPolicies.get(policyName);
353                         if (val != null) {
354                             mUsesPolicies |= 1 << val.intValue();
355                         } else {
356                             Log.w(TAG, "Unknown tag under uses-policies of "
357                                     + getComponent() + ": " + policyName);
358                         }
359                     }
360                 } else if (tagName.equals("support-transfer-ownership")) {
361                     if (parser.next() != XmlPullParser.END_TAG) {
362                         throw new XmlPullParserException(
363                                 "support-transfer-ownership tag must be empty.");
364                     }
365                     mSupportsTransferOwnership = true;
366                 }
367             }
368         } catch (NameNotFoundException e) {
369             throw new XmlPullParserException(
370                     "Unable to create context for: " + mActivityInfo.packageName);
371         } finally {
372             if (parser != null) parser.close();
373         }
374     }
375 
DeviceAdminInfo(Parcel source)376     DeviceAdminInfo(Parcel source) {
377         mActivityInfo = ActivityInfo.CREATOR.createFromParcel(source);
378         mUsesPolicies = source.readInt();
379         mSupportsTransferOwnership = source.readBoolean();
380     }
381 
382     /**
383      * Return the .apk package that implements this device admin.
384      */
getPackageName()385     public String getPackageName() {
386         return mActivityInfo.packageName;
387     }
388 
389     /**
390      * Return the class name of the receiver component that implements
391      * this device admin.
392      */
getReceiverName()393     public String getReceiverName() {
394         return mActivityInfo.name;
395     }
396 
397     /**
398      * Return the raw information about the receiver implementing this
399      * device admin.  Do not modify the returned object.
400      */
getActivityInfo()401     public ActivityInfo getActivityInfo() {
402         return mActivityInfo;
403     }
404 
405     /**
406      * Return the component of the receiver that implements this device admin.
407      */
408     @NonNull
getComponent()409     public ComponentName getComponent() {
410         return new ComponentName(mActivityInfo.packageName,
411                 mActivityInfo.name);
412     }
413 
414     /**
415      * Load the user-displayed label for this device admin.
416      *
417      * @param pm Supply a PackageManager used to load the device admin's
418      * resources.
419      */
loadLabel(PackageManager pm)420     public CharSequence loadLabel(PackageManager pm) {
421         return mActivityInfo.loadLabel(pm);
422     }
423 
424     /**
425      * Load user-visible description associated with this device admin.
426      *
427      * @param pm Supply a PackageManager used to load the device admin's
428      * resources.
429      */
loadDescription(PackageManager pm)430     public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
431         if (mActivityInfo.descriptionRes != 0) {
432             return pm.getText(mActivityInfo.packageName,
433                     mActivityInfo.descriptionRes, mActivityInfo.applicationInfo);
434         }
435         throw new NotFoundException();
436     }
437 
438     /**
439      * Load the user-displayed icon for this device admin.
440      *
441      * @param pm Supply a PackageManager used to load the device admin's
442      * resources.
443      */
loadIcon(PackageManager pm)444     public Drawable loadIcon(PackageManager pm) {
445         return mActivityInfo.loadIcon(pm);
446     }
447 
448     /**
449      * Returns whether this device admin would like to be visible to the
450      * user, even when it is not enabled.
451      */
isVisible()452     public boolean isVisible() {
453         return mVisible;
454     }
455 
456     /**
457      * Return true if the device admin has requested that it be able to use
458      * the given policy control.  The possible policy identifier inputs are:
459      * {@link #USES_POLICY_LIMIT_PASSWORD}, {@link #USES_POLICY_WATCH_LOGIN},
460      * {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_FORCE_LOCK},
461      * {@link #USES_POLICY_WIPE_DATA},
462      * {@link #USES_POLICY_EXPIRE_PASSWORD}, {@link #USES_ENCRYPTED_STORAGE},
463      * {@link #USES_POLICY_DISABLE_CAMERA}.
464      */
usesPolicy(int policyIdent)465     public boolean usesPolicy(int policyIdent) {
466         return (mUsesPolicies & (1<<policyIdent)) != 0;
467     }
468 
469     /**
470      * Return the XML tag name for the given policy identifier.  Valid identifiers
471      * are as per {@link #usesPolicy(int)}.  If the given identifier is not
472      * known, null is returned.
473      */
getTagForPolicy(int policyIdent)474     public String getTagForPolicy(int policyIdent) {
475         return sRevKnownPolicies.get(policyIdent).tag;
476     }
477 
478     /**
479      * Return true if this administrator can be a target in an ownership transfer.
480      */
supportsTransferOwnership()481     public boolean supportsTransferOwnership() {
482         return mSupportsTransferOwnership;
483     }
484 
485     /** @hide */
486     @UnsupportedAppUsage
getUsedPolicies()487     public ArrayList<PolicyInfo> getUsedPolicies() {
488         ArrayList<PolicyInfo> res = new ArrayList<PolicyInfo>();
489         for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
490             PolicyInfo pi = sPoliciesDisplayOrder.get(i);
491             if (usesPolicy(pi.ident)) {
492                 res.add(pi);
493             }
494         }
495         return res;
496     }
497 
498     /** @hide */
writePoliciesToXml(XmlSerializer out)499     public void writePoliciesToXml(XmlSerializer out)
500             throws IllegalArgumentException, IllegalStateException, IOException {
501         out.attribute(null, "flags", Integer.toString(mUsesPolicies));
502     }
503 
504     /** @hide */
readPoliciesFromXml(XmlPullParser parser)505     public void readPoliciesFromXml(XmlPullParser parser)
506             throws XmlPullParserException, IOException {
507         mUsesPolicies = Integer.parseInt(
508                 parser.getAttributeValue(null, "flags"));
509     }
510 
dump(Printer pw, String prefix)511     public void dump(Printer pw, String prefix) {
512         pw.println(prefix + "Receiver:");
513         mActivityInfo.dump(pw, prefix + "  ");
514     }
515 
516     @Override
toString()517     public String toString() {
518         return "DeviceAdminInfo{" + mActivityInfo.name + "}";
519     }
520 
521     /**
522      * Used to package this object into a {@link Parcel}.
523      *
524      * @param dest The {@link Parcel} to be written.
525      * @param flags The flags used for parceling.
526      */
writeToParcel(Parcel dest, int flags)527     public void writeToParcel(Parcel dest, int flags) {
528         mActivityInfo.writeToParcel(dest, flags);
529         dest.writeInt(mUsesPolicies);
530         dest.writeBoolean(mSupportsTransferOwnership);
531     }
532 
533     /**
534      * Used to make this class parcelable.
535      */
536     public static final @android.annotation.NonNull Parcelable.Creator<DeviceAdminInfo> CREATOR =
537             new Parcelable.Creator<DeviceAdminInfo>() {
538         public DeviceAdminInfo createFromParcel(Parcel source) {
539             return new DeviceAdminInfo(source);
540         }
541 
542         public DeviceAdminInfo[] newArray(int size) {
543             return new DeviceAdminInfo[size];
544         }
545     };
546 
describeContents()547     public int describeContents() {
548         return 0;
549     }
550 }
551