Save policy when saving account

Also add a loader to AccountSecurity, and ignore when a policy contains unsupported requirements.

b/11790165

Change-Id: Idd651153848eea3216656047c5aba3bbd750ca0a
diff --git a/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl b/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl
index 9d4be36..c284292 100755
--- a/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl
+++ b/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl
@@ -20,6 +20,9 @@
 interface IPolicyService {
     boolean isActive(in Policy policies);
     void setAccountHoldFlag(long accountId, boolean newState);
+    // Legacy compatability for Exchange shipped with KK
     void setAccountPolicy(long accountId, in Policy policy, String securityKey);
+    // New version
+    void setAccountPolicy2(long accountId, in Policy policy, String securityKey, boolean notify);
     oneway void remoteWipe();
 }
\ No newline at end of file
diff --git a/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java
index 347768b..fcd916f 100755
--- a/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java
+++ b/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java
@@ -70,12 +70,18 @@
     @Override
     public void setAccountPolicy(final long accountId, final Policy policy,
             final String securityKey) throws RemoteException {
+        setAccountPolicy2(accountId, policy, securityKey, true /* notify */);
+    }
+
+    @Override
+    public void setAccountPolicy2(final long accountId, final Policy policy,
+            final String securityKey, final boolean notify) throws RemoteException {
         setTask(new ProxyTask() {
             @Override
             public void run() throws RemoteException {
-                mService.setAccountPolicy(accountId, policy, securityKey);
+                mService.setAccountPolicy2(accountId, policy, securityKey, notify);
             }
-        }, "setAccountPolicy");
+        }, "setAccountPolicy2");
         waitForCompletion();
     }
 
@@ -126,8 +132,14 @@
 
     public static void setAccountPolicy(Context context, long accountId, Policy policy,
             String securityKey) {
+        setAccountPolicy2(context, accountId, policy, securityKey, true /* notify */);
+    }
+
+    public static void setAccountPolicy2(Context context, long accountId, Policy policy,
+            String securityKey, boolean notify) {
         try {
-            new PolicyServiceProxy(context).setAccountPolicy(accountId, policy, securityKey);
+            new PolicyServiceProxy(context).setAccountPolicy2(accountId, policy, securityKey,
+                    notify);
             return;
         } catch (RemoteException e) {
         }
diff --git a/src/com/android/email/SecurityPolicy.java b/src/com/android/email/SecurityPolicy.java
index de1b31d..de1a04e 100644
--- a/src/com/android/email/SecurityPolicy.java
+++ b/src/com/android/email/SecurityPolicy.java
@@ -583,7 +583,8 @@
         syncAccount(mContext, account);
     }
 
-    public void setAccountPolicy(long accountId, Policy policy, String securityKey) {
+    public void setAccountPolicy(long accountId, Policy policy, String securityKey,
+            boolean notify) {
         Account account = Account.restoreAccountWithId(mContext, accountId);
         Policy oldPolicy = null;
         if (account.mPolicyKey > 0) {
@@ -613,8 +614,10 @@
             LogUtils.d(Logging.LOG_TAG,
                     "Notify policies for " + account.mDisplayName + " not supported.");
             setHold = true;
-            NotificationController.getInstance(mContext).showSecurityUnsupportedNotification(
-                    account);
+            if (notify) {
+                NotificationController.getInstance(mContext).showSecurityUnsupportedNotification(
+                        account);
+            }
             // Erase data
             Uri uri = EmailProvider.uiUri("uiaccountdata", accountId);
             mContext.getContentResolver().delete(uri, null, null);
@@ -622,9 +625,11 @@
             if (policyChanged) {
                 LogUtils.d(Logging.LOG_TAG, "Notify policies for " + account.mDisplayName
                         + " changed.");
-                // Notify that policies changed
-                NotificationController.getInstance(mContext).showSecurityChangedNotification(
-                        account);
+                if (notify) {
+                    // Notify that policies changed
+                    NotificationController.getInstance(mContext).showSecurityChangedNotification(
+                            account);
+                }
             } else {
                 LogUtils.d(Logging.LOG_TAG, "Policy is active and unchanged; do not notify.");
             }
@@ -632,8 +637,11 @@
             setHold = true;
             LogUtils.d(Logging.LOG_TAG, "Notify policies for " + account.mDisplayName +
                     " are not being enforced.");
-            // Put up a notification
-            NotificationController.getInstance(mContext).showSecurityNeededNotification(account);
+            if (notify) {
+                // Put up a notification
+                NotificationController.getInstance(mContext).showSecurityNeededNotification(
+                        account);
+            }
         }
         // Set/clear the account hold.
         setAccountHoldFlag(mContext, account, setHold);
diff --git a/src/com/android/email/activity/setup/AccountSecurity.java b/src/com/android/email/activity/setup/AccountSecurity.java
index c25d26e..8736599 100644
--- a/src/com/android/email/activity/setup/AccountSecurity.java
+++ b/src/com/android/email/activity/setup/AccountSecurity.java
@@ -21,19 +21,25 @@
 import android.app.Dialog;
 import android.app.DialogFragment;
 import android.app.FragmentManager;
+import android.app.LoaderManager;
 import android.app.admin.DevicePolicyManager;
+import android.content.AsyncTaskLoader;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.Loader;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.text.TextUtils;
 
+import com.android.email.NotificationController;
 import com.android.email.R;
 import com.android.email.SecurityPolicy;
 import com.android.email.activity.ActivityHelper;
 import com.android.email2.ui.MailActivityEmail;
 import com.android.emailcommon.provider.Account;
 import com.android.emailcommon.provider.HostAuth;
+import com.android.emailcommon.provider.Policy;
 import com.android.emailcommon.utility.Utility;
 import com.android.mail.utils.LogUtils;
 
@@ -99,6 +105,8 @@
         return intent;
     }
 
+    private static final int ACCOUNT_POLICY_LOADER = 0;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -116,11 +124,81 @@
             return;
         }
 
-        mAccount = Account.restoreAccountWithId(AccountSecurity.this, accountId);
-        if (mAccount == null) {
-            finish();
-            return;
-        }
+        final Bundle b = new Bundle(1);
+        b.putLong(EXTRA_ACCOUNT_ID, accountId);
+
+        getLoaderManager().initLoader(ACCOUNT_POLICY_LOADER, b,
+                new LoaderManager.LoaderCallbacks<Account>() {
+            @Override
+            public Loader<Account> onCreateLoader(final int id, final Bundle args) {
+                final long accountId = args.getLong(EXTRA_ACCOUNT_ID);
+                return new AsyncTaskLoader<Account>(AccountSecurity.this) {
+                    volatile Account mData;
+
+                    @Override
+                    public Account loadInBackground() {
+                        final Account account = Account.restoreAccountWithId(AccountSecurity.this,
+                                accountId);
+                        if (account == null) {
+                            return null;
+                        }
+
+                        final long policyId = account.mPolicyKey;
+
+                        if (policyId == 0) {
+                            return account;
+                        }
+
+                        account.mPolicy = Policy.restorePolicyWithId(AccountSecurity.this,
+                                policyId);
+                        return account;
+                    }
+
+                    @Override
+                    public void deliverResult(final Account data) {
+                        if (isStarted()) {
+                            super.deliverResult(data);
+                        } else {
+                            mData = data;
+                        }
+                    }
+
+                    @Override
+                    protected void onStartLoading() {
+                        if (mData != null) {
+                            deliverResult(mData);
+                        } else {
+                            forceLoad();
+                        }
+                    }
+
+                    @Override
+                    protected void onStopLoading() {
+                        cancelLoad();
+                    }
+                };
+            }
+
+            @Override
+            public void onLoadFinished(final Loader<Account> loader, final Account data) {
+                if (data == null || (data.mPolicyKey != 0 && data.mPolicy == null)) {
+                    finish();
+                    LogUtils.d(TAG, "could not load account or policy in AccountSecurity");
+                    return;
+                }
+                finishCreate(data, showDialog, passwordExpiring, passwordExpired);
+                getLoaderManager().destroyLoader(ACCOUNT_POLICY_LOADER);
+            }
+
+            @Override
+            public void onLoaderReset(final Loader<Account> loader) {
+            }
+        });
+    }
+
+    private void finishCreate(final Account account, final boolean showDialog,
+            final boolean passwordExpiring, final boolean passwordExpired) {
+        mAccount = account;
 
         // Special handling for password expiration events
         if (passwordExpiring || passwordExpired) {
diff --git a/src/com/android/email/activity/setup/AccountSettingsUtils.java b/src/com/android/email/activity/setup/AccountSettingsUtils.java
index a2234c2..5505663 100644
--- a/src/com/android/email/activity/setup/AccountSettingsUtils.java
+++ b/src/com/android/email/activity/setup/AccountSettingsUtils.java
@@ -25,6 +25,7 @@
 import android.widget.EditText;
 
 import com.android.email.R;
+import com.android.email.SecurityPolicy;
 import com.android.email.provider.AccountBackupRestore;
 import com.android.emailcommon.Logging;
 import com.android.emailcommon.VendorPolicyLoader;
@@ -32,6 +33,7 @@
 import com.android.emailcommon.provider.Account;
 import com.android.emailcommon.provider.EmailContent.AccountColumns;
 import com.android.emailcommon.provider.QuickResponse;
+import com.android.emailcommon.service.PolicyServiceProxy;
 import com.android.emailcommon.utility.Utility;
 import com.android.mail.utils.LogUtils;
 import com.google.common.annotations.VisibleForTesting;
@@ -55,6 +57,22 @@
         if (!account.isSaved()) {
             account.save(context);
 
+            if (account.mPolicy != null) {
+                // TODO: we need better handling for unsupported policies
+                // For now, just clear the unsupported policies, as the server will (hopefully)
+                // just reject our sync attempts if it's not happy with half-measures
+                if (account.mPolicy.mProtocolPoliciesUnsupported != null) {
+                    LogUtils.d(LogUtils.TAG, "Clearing unsupported policies "
+                            + account.mPolicy.mProtocolPoliciesUnsupported);
+                    account.mPolicy.mProtocolPoliciesUnsupported = null;
+                }
+                PolicyServiceProxy.setAccountPolicy2(context,
+                        account.getId(),
+                        account.mPolicy,
+                        account.mSecuritySyncKey == null ? "" : account.mSecuritySyncKey,
+                        false /* notify */);
+            }
+
             // Set up default quick responses here...
             String[] defaultQuickResponses =
                 context.getResources().getStringArray(R.array.default_quick_responses);
diff --git a/src/com/android/email/service/PolicyService.java b/src/com/android/email/service/PolicyService.java
index aa4fdef..c045fab 100644
--- a/src/com/android/email/service/PolicyService.java
+++ b/src/com/android/email/service/PolicyService.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
+import android.os.RemoteException;
 
 import com.android.email.SecurityPolicy;
 import com.android.emailcommon.provider.Policy;
@@ -65,8 +66,14 @@
 
         @Override
         public void setAccountPolicy(long accountId, Policy policy, String securityKey) {
+            setAccountPolicy2(accountId, policy, securityKey, true /* notify */);
+        }
+
+        @Override
+        public void setAccountPolicy2(long accountId, Policy policy, String securityKey,
+                boolean notify) {
             try {
-                mSecurityPolicy.setAccountPolicy(accountId, policy, securityKey);
+                mSecurityPolicy.setAccountPolicy(accountId, policy, securityKey, notify);
             } catch (RuntimeException e) {
                 // Catch, log and rethrow the exception, as otherwise when the exception is
                 // ultimately handled, the complete stack trace is losk