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