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