Policy.java revision 745b33b8ff55e9a9c4871f07f9d97db893f784b2
1/* 2 * Copyright (C) 2011 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 17package com.android.emailcommon.provider; 18import android.app.admin.DevicePolicyManager; 19import android.content.ContentProviderOperation; 20import android.content.ContentResolver; 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.content.Context; 24import android.content.OperationApplicationException; 25import android.database.Cursor; 26import android.net.Uri; 27import android.os.Parcel; 28import android.os.Parcelable; 29import android.os.RemoteException; 30import android.util.Log; 31 32import com.android.emailcommon.utility.Utility; 33import com.google.common.annotations.VisibleForTesting; 34 35import java.util.ArrayList; 36 37/** 38 * The Policy class represents a set of security requirements that are associated with an Account. 39 * The requirements may be either device-specific (e.g. password) or application-specific (e.g. 40 * a limit on the sync window for the Account) 41 */ 42public final class Policy extends EmailContent implements EmailContent.PolicyColumns, Parcelable { 43 // STOPSHIP Change to false after a few days of debugging 44 public static final boolean DEBUG_POLICY = false; // DO NOT SUBMIT WITH THIS SET TO TRUE 45 public static final String TAG = "Email/Policy"; 46 47 public static final String TABLE_NAME = "Policy"; 48 @SuppressWarnings("hiding") 49 public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/policy"); 50 51 /* Convert days to mSec (used for password expiration) */ 52 private static final long DAYS_TO_MSEC = 24 * 60 * 60 * 1000; 53 /* Small offset (2 minutes) added to policy expiration to make user testing easier. */ 54 private static final long EXPIRATION_OFFSET_MSEC = 2 * 60 * 1000; 55 56 public static final int PASSWORD_MODE_NONE = 0; 57 public static final int PASSWORD_MODE_SIMPLE = 1; 58 public static final int PASSWORD_MODE_STRONG = 2; 59 60 public int mPasswordMode; 61 public int mPasswordMinLength; 62 public int mPasswordMaxFails; 63 public int mPasswordExpirationDays; 64 public int mPasswordHistory; 65 public int mPasswordComplexChars; 66 public int mMaxScreenLockTime; 67 public boolean mRequireRemoteWipe; 68 public boolean mRequireEncryption; 69 public boolean mRequireEncryptionExternal; 70 public boolean mRequireManualSyncWhenRoaming; 71 public boolean mDontAllowCamera; 72 public boolean mDontAllowAttachments; 73 public boolean mDontAllowHtml; 74 public int mMaxAttachmentSize; 75 public int mMaxTextTruncationSize; 76 public int mMaxHtmlTruncationSize; 77 public int mMaxEmailLookback; 78 public int mMaxCalendarLookback; 79 public boolean mPasswordRecoveryEnabled; 80 81 public static final int CONTENT_ID_COLUMN = 0; 82 public static final int CONTENT_PASSWORD_MODE_COLUMN = 1; 83 public static final int CONTENT_PASSWORD_MIN_LENGTH_COLUMN = 2; 84 public static final int CONTENT_PASSWORD_EXPIRATION_DAYS_COLUMN = 3; 85 public static final int CONTENT_PASSWORD_HISTORY_COLUMN = 4; 86 public static final int CONTENT_PASSWORD_COMPLEX_CHARS_COLUMN = 5; 87 public static final int CONTENT_PASSWORD_MAX_FAILS_COLUMN = 6; 88 public static final int CONTENT_MAX_SCREEN_LOCK_TIME_COLUMN = 7; 89 public static final int CONTENT_REQUIRE_REMOTE_WIPE_COLUMN = 8; 90 public static final int CONTENT_REQUIRE_ENCRYPTION_COLUMN = 9; 91 public static final int CONTENT_REQUIRE_ENCRYPTION_EXTERNAL_COLUMN = 10; 92 public static final int CONTENT_REQUIRE_MANUAL_SYNC_WHEN_ROAMING = 11; 93 public static final int CONTENT_DONT_ALLOW_CAMERA_COLUMN = 12; 94 public static final int CONTENT_DONT_ALLOW_ATTACHMENTS_COLUMN = 13; 95 public static final int CONTENT_DONT_ALLOW_HTML_COLUMN = 14; 96 public static final int CONTENT_MAX_ATTACHMENT_SIZE_COLUMN = 15; 97 public static final int CONTENT_MAX_TEXT_TRUNCATION_SIZE_COLUMN = 16; 98 public static final int CONTENT_MAX_HTML_TRUNCATION_SIZE_COLUMN = 17; 99 public static final int CONTENT_MAX_EMAIL_LOOKBACK_COLUMN = 18; 100 public static final int CONTENT_MAX_CALENDAR_LOOKBACK_COLUMN = 19; 101 public static final int CONTENT_PASSWORD_RECOVERY_ENABLED_COLUMN = 20; 102 103 public static final String[] CONTENT_PROJECTION = new String[] {RECORD_ID, 104 PolicyColumns.PASSWORD_MODE, PolicyColumns.PASSWORD_MIN_LENGTH, 105 PolicyColumns.PASSWORD_EXPIRATION_DAYS, PolicyColumns.PASSWORD_HISTORY, 106 PolicyColumns.PASSWORD_COMPLEX_CHARS, PolicyColumns.PASSWORD_MAX_FAILS, 107 PolicyColumns.MAX_SCREEN_LOCK_TIME, PolicyColumns.REQUIRE_REMOTE_WIPE, 108 PolicyColumns.REQUIRE_ENCRYPTION, PolicyColumns.REQUIRE_ENCRYPTION_EXTERNAL, 109 PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING, PolicyColumns.DONT_ALLOW_CAMERA, 110 PolicyColumns.DONT_ALLOW_ATTACHMENTS, PolicyColumns.DONT_ALLOW_HTML, 111 PolicyColumns.MAX_ATTACHMENT_SIZE, PolicyColumns.MAX_TEXT_TRUNCATION_SIZE, 112 PolicyColumns.MAX_HTML_TRUNCATION_SIZE, PolicyColumns.MAX_EMAIL_LOOKBACK, 113 PolicyColumns.MAX_CALENDAR_LOOKBACK, PolicyColumns.PASSWORD_RECOVERY_ENABLED 114 }; 115 116 public static final Policy NO_POLICY = new Policy(); 117 118 private static final String[] ATTACHMENT_RESET_PROJECTION = 119 new String[] {EmailContent.RECORD_ID, AttachmentColumns.SIZE, AttachmentColumns.FLAGS}; 120 private static final int ATTACHMENT_RESET_PROJECTION_ID = 0; 121 private static final int ATTACHMENT_RESET_PROJECTION_SIZE = 1; 122 private static final int ATTACHMENT_RESET_PROJECTION_FLAGS = 2; 123 124 public Policy() { 125 mBaseUri = CONTENT_URI; 126 // By default, the password mode is "none" 127 mPasswordMode = PASSWORD_MODE_NONE; 128 // All server policies require the ability to wipe the device 129 mRequireRemoteWipe = true; 130 } 131 132 public static Policy restorePolicyWithId(Context context, long id) { 133 return EmailContent.restoreContentWithId(context, Policy.class, Policy.CONTENT_URI, 134 Policy.CONTENT_PROJECTION, id); 135 } 136 137 public static long getAccountIdWithPolicyKey(Context context, long id) { 138 return Utility.getFirstRowLong(context, Account.CONTENT_URI, Account.ID_PROJECTION, 139 AccountColumns.POLICY_KEY + "=?", new String[] {Long.toString(id)}, null, 140 Account.ID_PROJECTION_COLUMN, Account.NO_ACCOUNT); 141 } 142 143 // We override this method to insure that we never write invalid policy data to the provider 144 @Override 145 public Uri save(Context context) { 146 normalize(); 147 return super.save(context); 148 } 149 150 public static void clearAccountPolicy(Context context, Account account) { 151 setAccountPolicy(context, account, null, null); 152 } 153 154 /** 155 * Convenience method for {@link #setAccountPolicy(Context, Account, Policy, String)}. 156 */ 157 @VisibleForTesting 158 public static void setAccountPolicy(Context context, long accountId, Policy policy, 159 String securitySyncKey) { 160 setAccountPolicy(context, Account.restoreAccountWithId(context, accountId), 161 policy, securitySyncKey); 162 } 163 164 /** 165 * Set the policy for an account atomically; this also removes any other policy associated with 166 * the account and sets the policy key for the account. If policy is null, the policyKey is 167 * set to 0 and the securitySyncKey to null 168 * @param context the caller's context 169 * @param account the account whose policy is to be set 170 * @param policy the policy to set, or null if we're clearing the policy 171 * @param securitySyncKey the security sync key for this account (ignored if policy is null) 172 */ 173 public static void setAccountPolicy(Context context, Account account, Policy policy, 174 String securitySyncKey) { 175 if (DEBUG_POLICY) { 176 Log.d(TAG, "Set policy for account " + account.mDisplayName + ": " + 177 ((policy == null) ? "none" : policy.toString())); 178 } 179 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); 180 181 // Make sure this is a valid policy set 182 if (policy != null) { 183 policy.normalize(); 184 // Add the new policy (no account will yet reference this) 185 ops.add(ContentProviderOperation.newInsert( 186 Policy.CONTENT_URI).withValues(policy.toContentValues()).build()); 187 // Make the policyKey of the account our newly created policy, and set the sync key 188 ops.add(ContentProviderOperation.newUpdate( 189 ContentUris.withAppendedId(Account.CONTENT_URI, account.mId)) 190 .withValueBackReference(AccountColumns.POLICY_KEY, 0) 191 .withValue(AccountColumns.SECURITY_SYNC_KEY, securitySyncKey) 192 .build()); 193 } else { 194 ops.add(ContentProviderOperation.newUpdate( 195 ContentUris.withAppendedId(Account.CONTENT_URI, account.mId)) 196 .withValue(AccountColumns.SECURITY_SYNC_KEY, null) 197 .withValue(AccountColumns.POLICY_KEY, 0) 198 .build()); 199 } 200 201 // Delete the previous policy associated with this account, if any 202 if (account.mPolicyKey > 0) { 203 ops.add(ContentProviderOperation.newDelete( 204 ContentUris.withAppendedId( 205 Policy.CONTENT_URI, account.mPolicyKey)).build()); 206 } 207 208 try { 209 context.getContentResolver().applyBatch(EmailContent.AUTHORITY, ops); 210 } catch (RemoteException e) { 211 // This is fatal to a remote process 212 throw new IllegalStateException("Exception setting account policy."); 213 } catch (OperationApplicationException e) { 214 // Can't happen; our provider doesn't throw this exception 215 } 216 } 217 218 /** 219 * Review all attachment records for this account, and reset the "don't allow download" flag 220 * as required by the account's new security policies 221 * @param context the caller's context 222 * @param account the account whose attachments need to be reviewed 223 * @param policy the new policy for this account 224 */ 225 public static void setAttachmentFlagsForNewPolicy(Context context, Account account, 226 Policy policy) { 227 // A nasty bit of work; start with all attachments for a given account 228 ContentResolver resolver = context.getContentResolver(); 229 Cursor c = resolver.query(Attachment.CONTENT_URI, ATTACHMENT_RESET_PROJECTION, 230 AttachmentColumns.ACCOUNT_KEY + "=?", new String[] {Long.toString(account.mId)}, 231 null); 232 ContentValues cv = new ContentValues(); 233 try { 234 // Get maximum allowed size (0 if we don't allow attachments at all) 235 int policyMax = policy.mDontAllowAttachments ? 0 : (policy.mMaxAttachmentSize > 0) ? 236 policy.mMaxAttachmentSize : Integer.MAX_VALUE; 237 while (c.moveToNext()) { 238 int flags = c.getInt(ATTACHMENT_RESET_PROJECTION_FLAGS); 239 int size = c.getInt(ATTACHMENT_RESET_PROJECTION_SIZE); 240 boolean wasRestricted = (flags & Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD) != 0; 241 boolean isRestricted = size > policyMax; 242 if (isRestricted != wasRestricted) { 243 if (isRestricted) { 244 flags |= Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD; 245 } else { 246 flags &= ~Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD; 247 } 248 long id = c.getLong(ATTACHMENT_RESET_PROJECTION_ID); 249 cv.put(AttachmentColumns.FLAGS, flags); 250 resolver.update(ContentUris.withAppendedId(Attachment.CONTENT_URI, id), 251 cv, null, null); 252 } 253 } 254 } finally { 255 c.close(); 256 } 257 } 258 259 /** 260 * Normalize the Policy. If the password mode is "none", zero out all password-related fields; 261 * zero out complex characters for simple passwords. 262 */ 263 public void normalize() { 264 if (mPasswordMode == PASSWORD_MODE_NONE) { 265 mPasswordMaxFails = 0; 266 mMaxScreenLockTime = 0; 267 mPasswordMinLength = 0; 268 mPasswordComplexChars = 0; 269 mPasswordHistory = 0; 270 mPasswordExpirationDays = 0; 271 } else { 272 if ((mPasswordMode != PASSWORD_MODE_SIMPLE) && 273 (mPasswordMode != PASSWORD_MODE_STRONG)) { 274 throw new IllegalArgumentException("password mode"); 275 } 276 // If we're only requiring a simple password, set complex chars to zero; note 277 // that EAS can erroneously send non-zero values in this case 278 if (mPasswordMode == PASSWORD_MODE_SIMPLE) { 279 mPasswordComplexChars = 0; 280 } 281 } 282 } 283 284 @Override 285 public boolean equals(Object other) { 286 if (!(other instanceof Policy)) return false; 287 Policy otherPolicy = (Policy)other; 288 if (mRequireEncryption != otherPolicy.mRequireEncryption) return false; 289 if (mRequireEncryptionExternal != otherPolicy.mRequireEncryptionExternal) return false; 290 if (mRequireRemoteWipe != otherPolicy.mRequireRemoteWipe) return false; 291 if (mMaxScreenLockTime != otherPolicy.mMaxScreenLockTime) return false; 292 if (mPasswordComplexChars != otherPolicy.mPasswordComplexChars) return false; 293 if (mPasswordExpirationDays != otherPolicy.mPasswordExpirationDays) return false; 294 if (mPasswordHistory != otherPolicy.mPasswordHistory) return false; 295 if (mPasswordMaxFails != otherPolicy.mPasswordMaxFails) return false; 296 if (mPasswordMinLength != otherPolicy.mPasswordMinLength) return false; 297 if (mPasswordMode != otherPolicy.mPasswordMode) return false; 298 if (mRequireManualSyncWhenRoaming != otherPolicy.mRequireManualSyncWhenRoaming) { 299 return false; 300 } 301 if (mDontAllowCamera != otherPolicy.mDontAllowCamera) return false; 302 if (mDontAllowAttachments != otherPolicy.mDontAllowAttachments) return false; 303 if (mDontAllowHtml != otherPolicy.mDontAllowHtml) return false; 304 if (mMaxAttachmentSize != otherPolicy.mMaxAttachmentSize) return false; 305 if (mMaxTextTruncationSize != otherPolicy.mMaxTextTruncationSize) return false; 306 if (mMaxHtmlTruncationSize != otherPolicy.mMaxHtmlTruncationSize) return false; 307 if (mMaxEmailLookback != otherPolicy.mMaxEmailLookback) return false; 308 if (mMaxCalendarLookback != otherPolicy.mMaxCalendarLookback) return false; 309 if (mPasswordRecoveryEnabled != otherPolicy.mPasswordRecoveryEnabled) return false; 310 return true; 311 } 312 313 @Override 314 public int hashCode() { 315 int code = mRequireEncryption ? 1 : 0; 316 code += (mRequireEncryptionExternal ? 1 : 0) << 1; 317 code += (mRequireRemoteWipe ? 1 : 0) << 2; 318 code += (mMaxScreenLockTime << 3); 319 code += (mPasswordComplexChars << 6); 320 code += (mPasswordExpirationDays << 12); 321 code += (mPasswordHistory << 15); 322 code += (mPasswordMaxFails << 18); 323 code += (mPasswordMinLength << 22); 324 code += (mPasswordMode << 26); 325 // Don't need to include the other fields 326 return code; 327 } 328 329 @Override 330 public void restore(Cursor cursor) { 331 mBaseUri = CONTENT_URI; 332 mId = cursor.getLong(CONTENT_ID_COLUMN); 333 mPasswordMode = cursor.getInt(CONTENT_PASSWORD_MODE_COLUMN); 334 mPasswordMinLength = cursor.getInt(CONTENT_PASSWORD_MIN_LENGTH_COLUMN); 335 mPasswordMaxFails = cursor.getInt(CONTENT_PASSWORD_MAX_FAILS_COLUMN); 336 mPasswordHistory = cursor.getInt(CONTENT_PASSWORD_HISTORY_COLUMN); 337 mPasswordExpirationDays = cursor.getInt(CONTENT_PASSWORD_EXPIRATION_DAYS_COLUMN); 338 mPasswordComplexChars = cursor.getInt(CONTENT_PASSWORD_COMPLEX_CHARS_COLUMN); 339 mMaxScreenLockTime = cursor.getInt(CONTENT_MAX_SCREEN_LOCK_TIME_COLUMN); 340 mRequireRemoteWipe = cursor.getInt(CONTENT_REQUIRE_REMOTE_WIPE_COLUMN) == 1; 341 mRequireEncryption = cursor.getInt(CONTENT_REQUIRE_ENCRYPTION_COLUMN) == 1; 342 mRequireEncryptionExternal = 343 cursor.getInt(CONTENT_REQUIRE_ENCRYPTION_EXTERNAL_COLUMN) == 1; 344 mRequireManualSyncWhenRoaming = 345 cursor.getInt(CONTENT_REQUIRE_MANUAL_SYNC_WHEN_ROAMING) == 1; 346 mDontAllowCamera = cursor.getInt(CONTENT_DONT_ALLOW_CAMERA_COLUMN) == 1; 347 mDontAllowAttachments = cursor.getInt(CONTENT_DONT_ALLOW_ATTACHMENTS_COLUMN) == 1; 348 mDontAllowHtml = cursor.getInt(CONTENT_DONT_ALLOW_HTML_COLUMN) == 1; 349 mMaxAttachmentSize = cursor.getInt(CONTENT_MAX_ATTACHMENT_SIZE_COLUMN); 350 mMaxTextTruncationSize = cursor.getInt(CONTENT_MAX_TEXT_TRUNCATION_SIZE_COLUMN); 351 mMaxHtmlTruncationSize = cursor.getInt(CONTENT_MAX_HTML_TRUNCATION_SIZE_COLUMN); 352 mMaxEmailLookback = cursor.getInt(CONTENT_MAX_EMAIL_LOOKBACK_COLUMN); 353 mMaxCalendarLookback = cursor.getInt(CONTENT_MAX_CALENDAR_LOOKBACK_COLUMN); 354 mPasswordRecoveryEnabled = cursor.getInt(CONTENT_PASSWORD_RECOVERY_ENABLED_COLUMN) == 1; 355 } 356 357 @Override 358 public ContentValues toContentValues() { 359 ContentValues values = new ContentValues(); 360 values.put(PolicyColumns.PASSWORD_MODE, mPasswordMode); 361 values.put(PolicyColumns.PASSWORD_MIN_LENGTH, mPasswordMinLength); 362 values.put(PolicyColumns.PASSWORD_MAX_FAILS, mPasswordMaxFails); 363 values.put(PolicyColumns.PASSWORD_HISTORY, mPasswordHistory); 364 values.put(PolicyColumns.PASSWORD_EXPIRATION_DAYS, mPasswordExpirationDays); 365 values.put(PolicyColumns.PASSWORD_COMPLEX_CHARS, mPasswordComplexChars); 366 values.put(PolicyColumns.MAX_SCREEN_LOCK_TIME, mMaxScreenLockTime); 367 values.put(PolicyColumns.REQUIRE_REMOTE_WIPE, mRequireRemoteWipe); 368 values.put(PolicyColumns.REQUIRE_ENCRYPTION, mRequireEncryption); 369 values.put(PolicyColumns.REQUIRE_ENCRYPTION_EXTERNAL, mRequireEncryptionExternal); 370 values.put(PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING, mRequireManualSyncWhenRoaming); 371 values.put(PolicyColumns.DONT_ALLOW_CAMERA, mDontAllowCamera); 372 values.put(PolicyColumns.DONT_ALLOW_ATTACHMENTS, mDontAllowAttachments); 373 values.put(PolicyColumns.DONT_ALLOW_HTML, mDontAllowHtml); 374 values.put(PolicyColumns.MAX_ATTACHMENT_SIZE, mMaxAttachmentSize); 375 values.put(PolicyColumns.MAX_TEXT_TRUNCATION_SIZE, mMaxTextTruncationSize); 376 values.put(PolicyColumns.MAX_HTML_TRUNCATION_SIZE, mMaxHtmlTruncationSize); 377 values.put(PolicyColumns.MAX_EMAIL_LOOKBACK, mMaxEmailLookback); 378 values.put(PolicyColumns.MAX_CALENDAR_LOOKBACK, mMaxCalendarLookback); 379 values.put(PolicyColumns.PASSWORD_RECOVERY_ENABLED, mPasswordRecoveryEnabled); 380 return values; 381 } 382 383 /** 384 * Helper to map our internal encoding to DevicePolicyManager password modes. 385 */ 386 public int getDPManagerPasswordQuality() { 387 switch (mPasswordMode) { 388 case PASSWORD_MODE_SIMPLE: 389 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 390 case PASSWORD_MODE_STRONG: 391 if (mPasswordComplexChars == 0) { 392 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; 393 } else { 394 return DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 395 } 396 default: 397 return DevicePolicyManager .PASSWORD_QUALITY_UNSPECIFIED; 398 } 399 } 400 401 /** 402 * Helper to map expiration times to the millisecond values used by DevicePolicyManager. 403 */ 404 public long getDPManagerPasswordExpirationTimeout() { 405 long result = mPasswordExpirationDays * DAYS_TO_MSEC; 406 // Add a small offset to the password expiration. This makes it easier to test 407 // by changing (for example) 1 day to 1 day + 5 minutes. If you set an expiration 408 // that is within the warning period, you should get a warning fairly quickly. 409 if (result > 0) { 410 result += EXPIRATION_OFFSET_MSEC; 411 } 412 return result; 413 } 414 415 private void appendPolicy(StringBuilder sb, String code, int value) { 416 sb.append(code); 417 sb.append(":"); 418 sb.append(value); 419 sb.append(" "); 420 } 421 422 @Override 423 public String toString() { 424 StringBuilder sb = new StringBuilder("["); 425 if (equals(NO_POLICY)) { 426 sb.append("No policies]"); 427 } else { 428 if (mPasswordMode == PASSWORD_MODE_NONE) { 429 sb.append("Pwd no "); 430 } else { 431 appendPolicy(sb, "Pwd strong", mPasswordMode == PASSWORD_MODE_STRONG ? 1 : 0); 432 appendPolicy(sb, "len", mPasswordMinLength); 433 appendPolicy(sb, "cmpx", mPasswordComplexChars); 434 appendPolicy(sb, "expy", mPasswordExpirationDays); 435 appendPolicy(sb, "hist", mPasswordHistory); 436 appendPolicy(sb, "fail", mPasswordMaxFails); 437 appendPolicy(sb, "idle", mMaxScreenLockTime); 438 } 439 appendPolicy(sb, "crypt", mRequireEncryption ? 1 : 0); 440 appendPolicy(sb, "crypt/ex", mRequireEncryptionExternal ? 1 : 0); 441 sb.append("]"); 442 } 443 return sb.toString(); 444 } 445 446 /** 447 * Supports Parcelable 448 */ 449 @Override 450 public int describeContents() { 451 return 0; 452 } 453 454 /** 455 * Supports Parcelable 456 */ 457 public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() { 458 public Policy createFromParcel(Parcel in) { 459 return new Policy(in); 460 } 461 462 public Policy[] newArray(int size) { 463 return new Policy[size]; 464 } 465 }; 466 467 /** 468 * Supports Parcelable 469 */ 470 @Override 471 public void writeToParcel(Parcel dest, int flags) { 472 // mBaseUri is not parceled 473 dest.writeLong(mId); 474 dest.writeInt(mPasswordMode); 475 dest.writeInt(mPasswordMinLength); 476 dest.writeInt(mPasswordMaxFails); 477 dest.writeInt(mPasswordHistory); 478 dest.writeInt(mPasswordExpirationDays); 479 dest.writeInt(mPasswordComplexChars); 480 dest.writeInt(mMaxScreenLockTime); 481 dest.writeInt(mRequireRemoteWipe ? 1 : 0); 482 dest.writeInt(mRequireEncryption ? 1 : 0); 483 dest.writeInt(mRequireEncryptionExternal ? 1 : 0); 484 dest.writeInt(mRequireManualSyncWhenRoaming ? 1 : 0); 485 dest.writeInt(mDontAllowCamera ? 1 : 0); 486 dest.writeInt(mDontAllowAttachments ? 1 : 0); 487 dest.writeInt(mDontAllowHtml ? 1 : 0); 488 dest.writeInt(mMaxAttachmentSize); 489 dest.writeInt(mMaxTextTruncationSize); 490 dest.writeInt(mMaxHtmlTruncationSize); 491 dest.writeInt(mMaxEmailLookback); 492 dest.writeInt(mMaxCalendarLookback); 493 dest.writeInt(mPasswordRecoveryEnabled ? 1 : 0); 494 } 495 496 /** 497 * Supports Parcelable 498 */ 499 public Policy(Parcel in) { 500 mBaseUri = CONTENT_URI; 501 mId = in.readLong(); 502 mPasswordMode = in.readInt(); 503 mPasswordMinLength = in.readInt(); 504 mPasswordMaxFails = in.readInt(); 505 mPasswordHistory = in.readInt(); 506 mPasswordExpirationDays = in.readInt(); 507 mPasswordComplexChars = in.readInt(); 508 mMaxScreenLockTime = in.readInt(); 509 mRequireRemoteWipe = in.readInt() == 1; 510 mRequireEncryption = in.readInt() == 1; 511 mRequireEncryptionExternal = in.readInt() == 1; 512 mRequireManualSyncWhenRoaming = in.readInt() == 1; 513 mDontAllowCamera = in.readInt() == 1; 514 mDontAllowAttachments = in.readInt() == 1; 515 mDontAllowHtml = in.readInt() == 1; 516 mMaxAttachmentSize = in.readInt(); 517 mMaxTextTruncationSize = in.readInt(); 518 mMaxHtmlTruncationSize = in.readInt(); 519 mMaxEmailLookback = in.readInt(); 520 mMaxCalendarLookback = in.readInt(); 521 mPasswordRecoveryEnabled = in.readInt() == 1; 522 } 523}