/** * Return a list of all Accounts in EmailProvider. Because the result of this call may be used in * account reconciliation, an exception is thrown if the result cannot be guaranteed accurate * * @param context the caller's context * @param accounts a list that Accounts will be added into * @return the list of Accounts * @throws ProviderUnavailableException if the list of Accounts cannot be guaranteed valid */ @Override public AccountList collectAccounts(Context context, AccountList accounts) { ContentResolver resolver = context.getContentResolver(); Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION, null, null, null); // We must throw here; callers might use the information we provide for reconciliation, etc. if (c == null) throw new ProviderUnavailableException(); try { ContentValues cv = new ContentValues(); while (c.moveToNext()) { long hostAuthId = c.getLong(Account.CONTENT_HOST_AUTH_KEY_RECV_COLUMN); if (hostAuthId > 0) { HostAuth ha = HostAuth.restoreHostAuthWithId(context, hostAuthId); if (ha != null && ha.mProtocol.equals(Eas.PROTOCOL)) { Account account = new Account(); account.restore(c); // Cache the HostAuth account.mHostAuthRecv = ha; accounts.add(account); // Fixup flags for inbox (should accept moved mail) Mailbox inbox = Mailbox.restoreMailboxOfType(context, account.mId, Mailbox.TYPE_INBOX); if (inbox != null && ((inbox.mFlags & Mailbox.FLAG_ACCEPTS_MOVED_MAIL) == 0)) { cv.put(MailboxColumns.FLAGS, inbox.mFlags | Mailbox.FLAG_ACCEPTS_MOVED_MAIL); resolver.update( ContentUris.withAppendedId(Mailbox.CONTENT_URI, inbox.mId), cv, null, null); } } } } } finally { c.close(); } return accounts; }
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(); } }