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