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