/**
  * API: Set/Clear the "hold" flag in any account. This flag serves a dual purpose: Setting it
  * gives us an indication that it was blocked, and clearing it gives EAS a signal to try syncing
  * again.
  *
  * @param context context
  * @param account the account whose hold flag is to be set/cleared
  * @param newState true = security hold, false = free to sync
  */
 public static void setAccountHoldFlag(Context context, Account account, boolean newState) {
   if (newState) {
     account.mFlags |= Account.FLAGS_SECURITY_HOLD;
   } else {
     account.mFlags &= ~Account.FLAGS_SECURITY_HOLD;
   }
   ContentValues cv = new ContentValues();
   cv.put(AccountColumns.FLAGS, account.mFlags);
   account.update(context, cv);
 }
  public static void updateAccountManagerType(
      Context context, android.accounts.Account amAccount, final Map<String, String> protocolMap) {
    final ContentResolver resolver = context.getContentResolver();
    final Cursor c =
        resolver.query(
            Account.CONTENT_URI,
            Account.CONTENT_PROJECTION,
            AccountColumns.EMAIL_ADDRESS + "=?",
            new String[] {amAccount.name},
            null);
    // That's odd, isn't it?
    if (c == null) return;
    try {
      if (c.moveToNext()) {
        // Get the EmailProvider Account/HostAuth
        final Account account = new Account();
        account.restore(c);
        final HostAuth hostAuth = HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv);
        if (hostAuth == null) {
          return;
        }

        final String newProtocol = protocolMap.get(hostAuth.mProtocol);
        if (newProtocol == null) {
          // This account doesn't need updating.
          return;
        }

        LogUtils.w(Logging.LOG_TAG, "Converting " + amAccount.name + " to " + newProtocol);

        final ContentValues accountValues = new ContentValues();
        int oldFlags = account.mFlags;

        // Mark the provider account incomplete so it can't get reconciled away
        account.mFlags |= Account.FLAGS_INCOMPLETE;
        accountValues.put(AccountColumns.FLAGS, account.mFlags);
        final Uri accountUri = ContentUris.withAppendedId(Account.CONTENT_URI, account.mId);
        resolver.update(accountUri, accountValues, null, null);

        // Change the HostAuth to reference the new protocol; this has to be done before
        // trying to create the AccountManager account (below)
        final ContentValues hostValues = new ContentValues();
        hostValues.put(HostAuth.PROTOCOL, newProtocol);
        resolver.update(
            ContentUris.withAppendedId(HostAuth.CONTENT_URI, hostAuth.mId), hostValues, null, null);
        LogUtils.w(Logging.LOG_TAG, "Updated HostAuths");

        try {
          // Get current settings for the existing AccountManager account
          boolean email = ContentResolver.getSyncAutomatically(amAccount, EmailContent.AUTHORITY);
          if (!email) {
            // Try our old provider name
            email = ContentResolver.getSyncAutomatically(amAccount, "com.android.email.provider");
          }
          final boolean contacts =
              ContentResolver.getSyncAutomatically(amAccount, ContactsContract.AUTHORITY);
          final boolean calendar =
              ContentResolver.getSyncAutomatically(amAccount, CalendarContract.AUTHORITY);
          LogUtils.w(
              Logging.LOG_TAG,
              "Email: " + email + ", Contacts: " + contacts + "," + " Calendar: " + calendar);

          // Get sync keys for calendar/contacts
          final String amName = amAccount.name;
          final String oldType = amAccount.type;
          ContentProviderClient client =
              context
                  .getContentResolver()
                  .acquireContentProviderClient(CalendarContract.CONTENT_URI);
          byte[] calendarSyncKey = null;
          try {
            calendarSyncKey =
                SyncStateContract.Helpers.get(
                    client,
                    asCalendarSyncAdapter(SyncState.CONTENT_URI, amName, oldType),
                    new android.accounts.Account(amName, oldType));
          } catch (RemoteException e) {
            LogUtils.w(Logging.LOG_TAG, "Get calendar key FAILED");
          } finally {
            client.release();
          }
          client =
              context
                  .getContentResolver()
                  .acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
          byte[] contactsSyncKey = null;
          try {
            contactsSyncKey =
                SyncStateContract.Helpers.get(
                    client,
                    ContactsContract.SyncState.CONTENT_URI,
                    new android.accounts.Account(amName, oldType));
          } catch (RemoteException e) {
            LogUtils.w(Logging.LOG_TAG, "Get contacts key FAILED");
          } finally {
            client.release();
          }
          if (calendarSyncKey != null) {
            LogUtils.w(Logging.LOG_TAG, "Got calendar key: " + new String(calendarSyncKey));
          }
          if (contactsSyncKey != null) {
            LogUtils.w(Logging.LOG_TAG, "Got contacts key: " + new String(contactsSyncKey));
          }

          // Set up a new AccountManager account with new type and old settings
          AccountManagerFuture<?> amFuture =
              setupAccountManagerAccount(context, account, email, calendar, contacts, null);
          finishAccountManagerBlocker(amFuture);
          LogUtils.w(Logging.LOG_TAG, "Created new AccountManager account");

          // TODO: Clean up how we determine the type.
          final String accountType = protocolMap.get(hostAuth.mProtocol + "_type");
          // Move calendar and contacts data from the old account to the new one.
          // We must do this before deleting the old account or the data is lost.
          moveCalendarData(context.getContentResolver(), amName, oldType, accountType);
          moveContactsData(context.getContentResolver(), amName, oldType, accountType);

          // Delete the AccountManager account
          amFuture = AccountManager.get(context).removeAccount(amAccount, null, null);
          finishAccountManagerBlocker(amFuture);
          LogUtils.w(Logging.LOG_TAG, "Deleted old AccountManager account");

          // Restore sync keys for contacts/calendar

          if (accountType != null && calendarSyncKey != null && calendarSyncKey.length != 0) {
            client =
                context
                    .getContentResolver()
                    .acquireContentProviderClient(CalendarContract.CONTENT_URI);
            try {
              SyncStateContract.Helpers.set(
                  client,
                  asCalendarSyncAdapter(SyncState.CONTENT_URI, amName, accountType),
                  new android.accounts.Account(amName, accountType),
                  calendarSyncKey);
              LogUtils.w(Logging.LOG_TAG, "Set calendar key...");
            } catch (RemoteException e) {
              LogUtils.w(Logging.LOG_TAG, "Set calendar key FAILED");
            } finally {
              client.release();
            }
          }
          if (accountType != null && contactsSyncKey != null && contactsSyncKey.length != 0) {
            client =
                context
                    .getContentResolver()
                    .acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
            try {
              SyncStateContract.Helpers.set(
                  client,
                  ContactsContract.SyncState.CONTENT_URI,
                  new android.accounts.Account(amName, accountType),
                  contactsSyncKey);
              LogUtils.w(Logging.LOG_TAG, "Set contacts key...");
            } catch (RemoteException e) {
              LogUtils.w(Logging.LOG_TAG, "Set contacts key FAILED");
            }
          }

          // That's all folks!
          LogUtils.w(Logging.LOG_TAG, "Account update completed.");
        } finally {
          // Clear the incomplete flag on the provider account
          accountValues.put(AccountColumns.FLAGS, oldFlags);
          resolver.update(accountUri, accountValues, null, null);
          LogUtils.w(Logging.LOG_TAG, "[Incomplete flag cleared]");
        }
      }
    } finally {
      c.close();
    }
  }