Example usage for android.accounts Account Account

List of usage examples for android.accounts Account Account

Introduction

In this page you can find the example usage for android.accounts Account Account.

Prototype

public Account(@NonNull Account other, @NonNull String accessId) 

Source Link

Usage

From source file:com.hybris.mobile.app.commerce.CommerceApplicationBase.java

/**
 * Add a default account to the sync adapter
 *//*from w  w  w .  j  a  v  a 2s.  c  o  m*/
private void addCatalogSyncAdapterDefaultAccount() {
    AccountManager accountManager = (AccountManager) getSystemService(ACCOUNT_SERVICE);
    accountManager.addAccountExplicitly(
            new Account(getString(R.string.account_name), getString(R.string.account_type)), null, null);
}

From source file:org.opendatakit.sync.aggregate.AggregateSynchronizer.java

public String updateAccessToken() throws InvalidAuthTokenException {
    AccountManager accountManager = AccountManager.get(context);
    try {/*from   ww  w  .  j  a  v a  2s .  c om*/
        SyncPreferences prefs = new SyncPreferences(context, appName);
        Account account = new Account(prefs.getAccount(), ACCOUNT_TYPE_G);
        this.accessToken = accountManager.blockingGetAuthToken(account, authString, true);
        return accessToken;
    } catch (Exception e) {
        e.printStackTrace();
        throw new InvalidAuthTokenException("unable to update access token -- please re-authorize");
    }
}

From source file:org.mozilla.gecko.fxa.authenticator.AndroidFxAccount.java

public static AndroidFxAccount addAndroidAccount(Context context, String email, String profile,
        String idpServerURI, String tokenServerURI, String profileServerURI, State state,
        final Map<String, Boolean> authoritiesToSyncAutomaticallyMap, final int accountVersion,
        final boolean fromPickle, ExtendedJSONObject bundle)
        throws UnsupportedEncodingException, GeneralSecurityException, URISyntaxException {
    if (email == null) {
        throw new IllegalArgumentException("email must not be null");
    }//ww  w  .j  a  v a2 s  . c  o m
    if (profile == null) {
        throw new IllegalArgumentException("profile must not be null");
    }
    if (idpServerURI == null) {
        throw new IllegalArgumentException("idpServerURI must not be null");
    }
    if (tokenServerURI == null) {
        throw new IllegalArgumentException("tokenServerURI must not be null");
    }
    if (profileServerURI == null) {
        throw new IllegalArgumentException("profileServerURI must not be null");
    }
    if (state == null) {
        throw new IllegalArgumentException("state must not be null");
    }

    // TODO: Add migration code.
    if (accountVersion != CURRENT_ACCOUNT_VERSION) {
        throw new IllegalStateException("Could not create account of version " + accountVersion
                + ". Current version is " + CURRENT_ACCOUNT_VERSION + ".");
    }

    // Android has internal restrictions that require all values in this
    // bundle to be strings. *sigh*
    Bundle userdata = new Bundle();
    userdata.putString(ACCOUNT_KEY_ACCOUNT_VERSION, "" + CURRENT_ACCOUNT_VERSION);
    userdata.putString(ACCOUNT_KEY_IDP_SERVER, idpServerURI);
    userdata.putString(ACCOUNT_KEY_TOKEN_SERVER, tokenServerURI);
    userdata.putString(ACCOUNT_KEY_PROFILE_SERVER, profileServerURI);
    userdata.putString(ACCOUNT_KEY_PROFILE, profile);

    if (bundle == null) {
        bundle = new ExtendedJSONObject();
        // TODO: How to upgrade?
        bundle.put(BUNDLE_KEY_BUNDLE_VERSION, CURRENT_BUNDLE_VERSION);
    }
    bundle.put(BUNDLE_KEY_STATE_LABEL, state.getStateLabel().name());
    bundle.put(BUNDLE_KEY_STATE, state.toJSONObject().toJSONString());

    userdata.putString(ACCOUNT_KEY_DESCRIPTOR, bundle.toJSONString());

    Account account = new Account(email, FxAccountConstants.ACCOUNT_TYPE);
    AccountManager accountManager = AccountManager.get(context);
    // We don't set an Android password, because we don't want to persist the
    // password (or anything else as powerful as the password). Instead, we
    // internally manage a sessionToken with a remotely owned lifecycle.
    boolean added = accountManager.addAccountExplicitly(account, null, userdata);
    if (!added) {
        return null;
    }

    // Try to work around an intermittent issue described at
    // http://stackoverflow.com/a/11698139.  What happens is that tests that
    // delete and re-create the same account frequently will find the account
    // missing all or some of the userdata bundle, possibly due to an Android
    // AccountManager caching bug.
    for (String key : userdata.keySet()) {
        accountManager.setUserData(account, key, userdata.getString(key));
    }

    AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);

    if (!fromPickle) {
        fxAccount.clearSyncPrefs();
    }

    fxAccount.setAuthoritiesToSyncAutomaticallyMap(authoritiesToSyncAutomaticallyMap);

    return fxAccount;
}

From source file:saschpe.birthdays.service.CalendarSyncService.java

private static Cursor getContactsEvents(Context context, ContentResolver contentResolver) {
    // Account blacklist from our provider
    List<Account> accountBlacklist = AccountProviderHelper.getAccountList(context);

    List<String> addedEventsIdentifiers = new ArrayList<>();

    /* 1. Get all raw contacts with their corresponding Account name and type (only raw
     *    contacts get Account affiliation) */
    Uri rawContactsUri = ContactsContract.RawContacts.CONTENT_URI;
    String[] rawContactsProjection = new String[] { ContactsContract.RawContacts._ID,
            ContactsContract.RawContacts.CONTACT_ID, ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY,
            ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE };
    Cursor rawContacts = contentResolver.query(rawContactsUri, rawContactsProjection, null, null, null);

    /* 2. Go over all raw contacts and check if the Account is allowed. If account is allowed,
     *    get display name and lookup key and all events for this contact. Build a new
     *    MatrixCursor out of this data that can be used. */
    String[] columns = new String[] { BaseColumns._ID, ContactsContract.Data.DISPLAY_NAME,
            ContactsContract.Data.LOOKUP_KEY, ContactsContract.CommonDataKinds.Event.START_DATE,
            ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.LABEL, };
    MatrixCursor mc = new MatrixCursor(columns);
    int mcIndex = 0;
    try {//from   w w  w.  j a v  a 2s . co  m
        while (rawContacts != null && rawContacts.moveToNext()) {
            long rawId = rawContacts.getLong(rawContacts.getColumnIndex(ContactsContract.RawContacts._ID));
            String accountType = rawContacts
                    .getString(rawContacts.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE));
            String accountName = rawContacts
                    .getString(rawContacts.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_NAME));

            // 2a. Check if Account is allowed (not in blacklist)
            boolean addEvent;
            if (TextUtils.isEmpty(accountType) || TextUtils.isEmpty(accountName)) {
                // Workaround: Simply add events without proper Account
                addEvent = true;
            } else {
                Account account = new Account(accountName, accountType);
                addEvent = !accountBlacklist.contains(account);
            }

            if (addEvent) {
                String displayName = null;
                String lookupKey = null;

                // 2b. Get display name and lookup key from normal contact table
                String[] displayProjection = new String[] { ContactsContract.Data.RAW_CONTACT_ID,
                        ContactsContract.Data.DISPLAY_NAME, ContactsContract.Data.LOOKUP_KEY };
                String displayWhere = ContactsContract.Data.RAW_CONTACT_ID + "= ?";
                String[] displaySelectionArgs = new String[] { String.valueOf(rawId) };
                Cursor displayCursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
                        displayProjection, displayWhere, displaySelectionArgs, null);
                try {
                    if (displayCursor != null && displayCursor.moveToNext()) {
                        displayName = displayCursor
                                .getString(displayCursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
                        lookupKey = displayCursor
                                .getString(displayCursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY));
                    }
                } finally {
                    if (displayCursor != null && !displayCursor.isClosed()) {
                        displayCursor.close();
                    }
                }

                /* 2c. Get all events for this raw contact. We don't get this information for
                 *     the (merged) contact table, but from the raw contact. If we would query
                 *     this information from the contact table, we would also get events that
                 *     should have been filtered. */
                Uri thisRawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
                        rawId);
                Uri entityUri = Uri.withAppendedPath(thisRawContactUri,
                        ContactsContract.RawContacts.Entity.CONTENT_DIRECTORY);
                String[] eventsProjection = new String[] { ContactsContract.RawContacts._ID,
                        ContactsContract.RawContacts.Entity.DATA_ID,
                        ContactsContract.CommonDataKinds.Event.START_DATE,
                        ContactsContract.CommonDataKinds.Event.TYPE,
                        ContactsContract.CommonDataKinds.Event.LABEL };
                String eventsWhere = ContactsContract.RawContacts.Entity.MIMETYPE + " = ? AND "
                        + ContactsContract.RawContacts.Entity.DATA_ID + " IS NOT NULL";
                String[] eventsSelectionArgs = new String[] {
                        ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE };
                Cursor eventsCursor = contentResolver.query(entityUri, eventsProjection, eventsWhere,
                        eventsSelectionArgs, null);
                try {
                    while (eventsCursor != null && eventsCursor.moveToNext()) {
                        String startDate = eventsCursor.getString(
                                eventsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.START_DATE));
                        int type = eventsCursor.getInt(
                                eventsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.TYPE));
                        String label = eventsCursor.getString(
                                eventsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LABEL));

                        /* 2d. Add this information to our MatrixCursor if not already added
                         *     previously. If two Event Reminder accounts have the same contact
                         *     with duplicated events, the event will already be in the HashSet
                         *     addedEventsIdentifiers.
                         *
                         *     eventIdentifier does not include startDate, because the
                         *     String formats of startDate differ between accounts. */
                        //String eventIdentifier = lookupKey + type + label;
                        String eventIdentifier = lookupKey + type;
                        if (addedEventsIdentifiers.contains(eventIdentifier)) {
                            Log.d(TAG, "Duplicate event was not added!");
                        } else {
                            Log.d(TAG, "Event was added with identifier " + eventIdentifier);

                            addedEventsIdentifiers.add(eventIdentifier);

                            mc.newRow().add(mcIndex).add(displayName).add(lookupKey).add(startDate).add(type)
                                    .add(label);
                            mcIndex++;
                        }

                    }
                } finally {
                    if (eventsCursor != null && !eventsCursor.isClosed()) {
                        eventsCursor.close();
                    }
                }
            }
        }
    } finally {
        if (rawContacts != null && !rawContacts.isClosed()) {
            rawContacts.close();
        }
    }
    /*if (BuildConfig.DEBUG) {
    DatabaseUtils.dumpCursor(mc);
    }*/
    return mc;
}

From source file:com.oxplot.contactphotosync.AssignContactPhotoActivity.java

@SuppressWarnings("unchecked")
@Override//from w  w  w.  j a va  2s .  co  m
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    switch (item.getItemId()) {

    case android.R.id.home:
        Intent upIntent = new Intent(this, SelectAccountActivity.class);
        if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
            TaskStackBuilder.create(this).addNextIntent(upIntent).startActivities();
        } else {
            NavUtils.navigateUpTo(this, upIntent);
        }
        return true;

    case R.id.menu_sync_now:

        // This is a convenient way of enabling and running the contact photo
        // sync.

        Account a = new Account(account, ACCOUNT_TYPE);
        ContentResolver.setSyncAutomatically(a, CONTACT_PHOTO_AUTHORITY, true);
        ContentResolver.requestSync(a, CONTACT_PHOTO_AUTHORITY, new Bundle());
        Toast.makeText(this, getResources().getString(R.string.sync_requested), Toast.LENGTH_LONG).show();
        break;

    case R.id.menu_download_all:
    case R.id.menu_upload_all:
        new DownloadUploadTask(item.getItemId() == R.id.menu_download_all ? DownloadUploadTask.TYPE_DOWNLOAD
                : DownloadUploadTask.TYPE_UPLOAD)
                        .execute(((ContactAdapter) contactList.getAdapter()).getBackingList());

        break;

    case R.id.menu_refresh:

        // XXX This is ugly and hackish. This of course doesn't stop us from being
        // lazy and using it here.

        onPause();
        onResume();
        break;
    }
    return super.onOptionsItemSelected(item);
}

From source file:com.amazonaws.mobile.auth.google.GoogleSignInProvider.java

private String getGoogleAuthToken(final String accountEmail) throws GoogleAuthException, IOException {
    Log.d(LOG_TAG, "Google provider getting token...");

    final Account googleAccount = new Account(accountEmail, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
    final String scopes = "audience:server:client_id:" + getGoogleClientId();

    // Retrieve the Google token.
    final String token = GoogleAuthUtil.getToken(context, googleAccount, scopes);
    // UserRecoverableAuthException will be thrown from GoogleAuthUtil.getToken() if not signed in.

    if (token != null) {
        Log.d(LOG_TAG, "Google Token is OK. Token hashcode = " + token.hashCode());
    } else {//from   w w w.j  a  v  a2  s  .c  o m
        Log.d(LOG_TAG, "Google Token is NULL.");
    }

    return token;
}

From source file:com.busticket.amedora.busticketsrl.TicketingHomeActivity.java

/**
 * Create a new dummy account for the sync adapter
 *
 * @param context The application context
 *//*from w w  w . j a va2s . c o m*/
public static Account CreateSyncAccount(Context context) {
    // Create the account type and default account
    Account newAccount = new Account(ACCOUNT, ACCOUNT_TYPE);
    // Get an instance of the Android account manager
    AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
    /*
     * Add the account and account type, no password or user data
     * If successful, return the Account object, otherwise report an error.
     */
    if (accountManager.addAccountExplicitly(newAccount, null, null)) {
        /*
         * If you don't set android:syncable="true" in
         * in your <provider> element in the manifest,
         * then call context.setIsSyncable(account, AUTHORITY, 1)
         * here.
         */

    } else {
        /*
         * The account exists or some other error occurred. Log this, report it,
         * or handle it internally.
         */
        Log.d("SYNC ERR", "The account exists or some other error occurred. Log this, report it,");
    }
    return newAccount;
}

From source file:com.grepsound.activities.MainActivity.java

/**
 * Create a new dummy account for the sync adapter
 *
 * @param context The application context
 *///from   w w w  . j  av a 2s. c  om
public static Account CreateSyncAccount(Context context) {
    // Create the account type and default account
    Account newAccount = new Account(ACCOUNT, ACCOUNT_TYPE);
    // Get an instance of the Android account manager
    AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
    /*
     * Add the account and account type, no password or user data
     * If successful, return the Account object, otherwise report an error.
     */
    if (accountManager.addAccountExplicitly(newAccount, null, null)) {
        /*
         * If you don't set android:syncable="true" in
         * in your <provider> element in the manifest,
         * then call context.setIsSyncable(account, AUTHORITY, 1)
         * here.
         */
    } else {
        /*
         * The account exists or some other error occurred. Log this, report it,
         * or handle it internally.
         */
    }
    return newAccount;
}

From source file:com.kiddobloom.bucketlist.AuthenticatorActivity.java

@Override
public void onCompleted(GraphUser user, Response response) {
    // TODO Auto-generated method stub
    //Log.d("tagaa", "FacebookGetMe: oncomplete me request");

    if (response != null) {

        FacebookRequestError error = response.getError();
        if (error != null) {
            // failed to get user info from facebook - TOAST
            //Log.d("tagaa", "FacebookGetMe: failed to get user info from facebook: " + error);

            Toast.makeText(getApplicationContext(),
                    "Failed to retrieve information from Facebook - OFFLINE mode", Toast.LENGTH_SHORT).show();

            saveState(StateMachine.OFFLINE_STATE);
            saveStatus(StateMachine.ERROR_STATUS);
            saveError(StateMachine.FB_GET_ME_FAILED_ERROR);
            goToBucketListActivity();/*from   ww w. j a  v  a2s . c o  m*/
            return;
        }
    }

    if (user != null) {

        boolean registered = false;
        final Account account;

        // if we get to this point, we know that the network is OK
        // we can continue server registration

        //Log.d("tagaa", "FacebookGetMe: me = " + user);

        // check whether (com.kidobloom) type account has been created for the fb-userid
        // if account db is empty - create a new account using the fb-userid
        // else if an account already exists, check to see if it matches the current fb-userid
        // if account exists and matches the fb-userid, do nothing
        // otherwise replace the account with the new fb-userid
        AccountManager accountManager = AccountManager.get(getApplicationContext());
        Account[] accounts = accountManager.getAccountsByType("com.kiddobloom");

        if (accounts.length <= 0) {
            //Log.d("tagaa", "FacebookGetMe: no account exists");
            // create a new account
            account = new Account(user.getId(), Constants.ACCOUNT_TYPE);
            am.addAccountExplicitly(account, null, null);
            ContentResolver.setSyncAutomatically(account, MyContentProvider.AUTHORITY, true);
            registered = false;
        } else {
            // get the first account
            //Log.d("tagaa", "FacebookGetMe: account = " + accounts[0].name);

            if (accounts[0].name.equals(user.getId())) {
                registered = true;
                //Log.d("tagaa", "FacebookGetMe: account for facebookId = " + user.getId() + " already created");
            } else {
                //Log.d("tag", "FacebookGetMe: user switched account");
                // remove the account first
                am.removeAccount(accounts[0], null, null);

                // add new account with the new facebook userid
                account = new Account(user.getId(), Constants.ACCOUNT_TYPE);
                am.addAccountExplicitly(account, null, null);
                ContentResolver.setSyncAutomatically(account, MyContentProvider.AUTHORITY, true);

                // update the registered flag so facebook ID gets re-registered
                registered = false;
            }
        }

        // at this point, an account should already be created
        // store the userid and registered boolean in preferences db
        saveFbUserId(user.getId());
        saveUserIdRegistered(registered);

        saveState(StateMachine.FB_GET_FRIENDS_STATE);
        saveStatus(StateMachine.TRANSACTING_STATUS);
        saveError(StateMachine.NO_ERROR);

        // request facebook friends list
        Request.executeMyFriendsRequestAsync(response.getRequest().getSession(), this);

    } else {
        // throw an exception here - facebook does not indicate error but user is null 
        //Log.d("tagaa", "FacebookGetMe: failed to get user info from facebook - OFFLINE mode");

        Toast.makeText(getApplicationContext(), "Failed to retrieve information from Facebook",
                Toast.LENGTH_SHORT).show();

        saveState(StateMachine.OFFLINE_STATE);
        saveStatus(StateMachine.ERROR_STATUS);
        saveError(StateMachine.FB_GET_ME_FAILED_ERROR);
        goToBucketListActivity();
    }
}

From source file:mobisocial.musubi.service.AddressBookUpdateHandler.java

@Override
public void onChange(boolean selfChange) {
    final DatabaseManager dbManager = new DatabaseManager(mContext);
    if (!dbManager.getIdentitiesManager().hasConnectedAccounts()) {
        Log.w(TAG, "no connected accounts, skipping friend import");
        return;/*ww  w  . j a  va2s  .  c  om*/
    }

    //a new meta contact appears (and the previous ones disappear) if the user merges
    //or if a new entry is added, we can detect the ones that have changed by
    //this condition
    long highestContactIdAlreadySeen = dbManager.getContactDataVersionManager().getMaxContactIdSeen();
    //a new data item corresponds with a new contact, but its possible
    //that a users just adds a new contact method to an existing contact
    //and we need to detect that
    long highestDataIdAlreadySeen = dbManager.getContactDataVersionManager().getMaxDataIdSeen();

    // BJD -- this didn't end up being faster once all import features were added.
    /*if (highestContactIdAlreadySeen == -1) {
       importFullAddressBook(mContext);
       return;
    }*/
    long now = System.currentTimeMillis();
    if (mLastRun + ONCE_PER_PERIOD > now) {
        //wake up when the period expires
        if (!mScheduled) {
            new Handler(mThread.getLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScheduled = false;
                    dispatchChange(false);
                }
            }, ONCE_PER_PERIOD - (now - mLastRun) + 1);
        }
        mScheduled = true;
        //skip this update
        return;
    }
    Log.i(TAG, "waking up to handle contact changes...");
    boolean identityAdded = false, profileDataChanged = false;
    Date start = new Date();

    assert (SYNC_EMAIL);
    String account_type_selection = getAccountSelectionString();

    Cursor c = mContext.getContentResolver().query(
            ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.Data._ID,
                    ContactsContract.Data.DATA_VERSION, ContactsContract.Data.CONTACT_ID },
            "(" + ContactsContract.Data.DATA_VERSION + ">0 OR " + //maybe updated
                    ContactsContract.Data.CONTACT_ID + ">? OR " + //definitely new or merged
                    ContactsContract.Data._ID + ">? " + //definitely added a data item
                    ") AND (" + ContactsContract.RawContacts.ACCOUNT_TYPE + "<>'" + mAccountType + "'"
                    + ") AND (" + NAME_OR_OTHER_SELECTION + account_type_selection + ")", // All known contacts.
            new String[] { String.valueOf(highestContactIdAlreadySeen),
                    String.valueOf(highestDataIdAlreadySeen) },
            null);

    if (c == null) {
        Log.e(TAG, "no valid cursor", new Throwable());
        mContext.getContentResolver().notifyChange(MusubiService.ADDRESS_BOOK_SCANNED, this);
        return;
    }

    HashMap<Pair<String, String>, MMyAccount> account_mapping = new HashMap<Pair<String, String>, MMyAccount>();
    int max_changes = c.getCount();
    TLongArrayList raw_data_ids = new TLongArrayList(max_changes);
    TLongArrayList versions = new TLongArrayList(max_changes);
    long new_max_data_id = highestDataIdAlreadySeen;
    long new_max_contact_id = highestContactIdAlreadySeen;
    TLongHashSet potentially_changed = new TLongHashSet();
    try {
        //the cursor points to a list of raw contact data items that may have changed
        //the items will include a type specific field that we are interested in updating
        //it is possible that multiple data item entries mention the same identifier
        //so we build a list of contacts to update and then perform synchronization
        //by refreshing given that we know the top level contact id.
        if (DBG)
            Log.d(TAG, "Scanning " + c.getCount() + " contacts...");
        while (c.moveToNext()) {
            if (DBG)
                Log.v(TAG, "check for updates of contact " + c.getLong(0));

            long raw_data_id = c.getLong(0);
            long version = c.getLong(1);
            long contact_id = c.getLong(2);

            //if the contact was split or merged, then we get a higher contact id
            //so if we have a higher id, data version doesnt really matter
            if (contact_id <= highestContactIdAlreadySeen) {
                //the data associated with this contact may not be dirty
                //we just can't do the join against our table because thise
                //api is implmented over the content provider
                if (dbManager.getContactDataVersionManager().getVersion(raw_data_id) == version)
                    continue;
            } else {
                new_max_contact_id = Math.max(new_max_contact_id, contact_id);
            }
            raw_data_ids.add(raw_data_id);
            versions.add(version);
            potentially_changed.add(contact_id);
            new_max_data_id = Math.max(new_max_data_id, raw_data_id);
        }
        if (DBG)
            Log.d(TAG, "Finished iterating over " + c.getCount() + " contacts for " + potentially_changed.size()
                    + " candidates.");
    } finally {
        c.close();
    }
    if (potentially_changed.size() == 0) {
        Log.w(TAG,
                "possible bug, woke up to update contacts, but no change was detected; there are extra wakes so it could be ok");
    }

    final SQLiteDatabase db = dbManager.getDatabase();

    Pattern emailPattern = getEmailPattern();
    Pattern numberPattern = getNumberPattern();
    //slice it up so we don't use too much system resource on keeping a lot of state in memory
    int total = potentially_changed.size();
    sAddressBookTotal = total;
    sAddressBookPosition = 0;

    final TLongArrayList slice_of_changed = new TLongArrayList(BATCH_SIZE);
    final StringBuilder to_fetch = new StringBuilder();
    final HashMap<Pair<String, String>, TLongHashSet> ids_for_account = new HashMap<Pair<String, String>, TLongHashSet>();
    final TLongObjectHashMap<String> names = new TLongObjectHashMap<String>();

    TLongIterator it = potentially_changed.iterator();
    for (int i = 0; i < total && it.hasNext();) {
        sAddressBookPosition = i;

        if (BootstrapActivity.isBootstrapped()) {
            try {
                Thread.sleep(mSleepTime * SLEEP_SCALE);
            } catch (InterruptedException e) {
            }
        }

        slice_of_changed.clear();
        ids_for_account.clear();
        names.clear();

        int max = i + BATCH_SIZE;
        for (; i < max && it.hasNext(); ++i) {
            slice_of_changed.add(it.next());
        }

        if (DBG)
            Log.v(TAG, "looking up names ");
        to_fetch.setLength(0);
        to_fetch.append(ContactsContract.Contacts._ID + " IN ");
        SQLClauseHelper.appendArray(to_fetch, slice_of_changed.iterator());
        //lookup the fields we care about from a user profile perspective
        c = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
                new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, },
                to_fetch.toString(), null, null);
        try {
            while (c.moveToNext()) {
                long id = c.getLong(0);
                String name = c.getString(1);
                if (name == null)
                    continue;
                //reject names that are just the email address or are just a number 
                //the default for android is just to propagate this as the name
                //if there is no name
                if (emailPattern.matcher(name).matches() || numberPattern.matcher(name).matches())
                    continue;
                names.put(id, name);
            }
        } finally {
            c.close();
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            db.beginTransactionNonExclusive();
        } else {
            db.beginTransaction();
        }

        long before = SystemClock.elapsedRealtime();
        SliceUpdater updater = new SliceUpdater(dbManager, slice_of_changed, ids_for_account, names,
                account_type_selection);
        long after = SystemClock.elapsedRealtime();
        mSleepTime = (mSleepTime + after - before) / 2;
        slice_of_changed.forEach(updater);
        profileDataChanged |= updater.profileDataChanged;
        identityAdded |= updater.identityAdded;
        db.setTransactionSuccessful();
        db.endTransaction();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            db.beginTransactionNonExclusive();
        } else {
            db.beginTransaction();
        }
        //add all detected members to account feed
        for (Entry<Pair<String, String>, TLongHashSet> e : ids_for_account.entrySet()) {
            Pair<String, String> k = e.getKey();
            TLongHashSet v = e.getValue();
            MMyAccount cached_account = account_mapping.get(k);
            if (cached_account == null) {
                cached_account = lookupOrCreateAccount(dbManager, k.getValue0(), k.getValue1());
                prepareAccountWhitelistFeed(dbManager.getMyAccountManager(), dbManager.getFeedManager(),
                        cached_account);
                account_mapping.put(k, cached_account);
            }

            final MMyAccount account = cached_account;
            v.forEach(new TLongProcedure() {
                @Override
                public boolean execute(long id) {
                    dbManager.getFeedManager().ensureFeedMember(account.feedId_, id);
                    db.yieldIfContendedSafely(75);
                    return true;
                }
            });
        }
        db.setTransactionSuccessful();
        db.endTransaction();
    }

    sAddressBookTotal = sAddressBookPosition = 0;

    //TODO: handle deleted
    //for all android data ids in our table, check if they still exist in the
    //contacts table, probably in batches of 100 or something.  if they don't
    //null them out.  this is annoyingly non-differential.

    //TODO: adding friend should update accepted feed status, however,
    //if a crashe happens for whatever reason, then its possible that this may need to
    //be run for identities which actually exist in the db.  so this update code
    //needs to do the feed accepted status change for all users that were touched
    //by the profile update process

    //update the version ids so we can be faster on subsequent runs
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        db.beginTransactionNonExclusive();
    } else {
        db.beginTransaction();
    }
    int changed_data_rows = raw_data_ids.size();
    for (int i = 0; i < changed_data_rows; ++i) {
        dbManager.getContactDataVersionManager().setVersion(raw_data_ids.get(i), versions.get(i));
    }
    db.setTransactionSuccessful();
    db.endTransaction();

    dbManager.getContactDataVersionManager().setMaxDataIdSeen(new_max_data_id);
    dbManager.getContactDataVersionManager().setMaxContactIdSeen(new_max_contact_id);
    ContentResolver resolver = mContext.getContentResolver();

    Date end = new Date();
    double time = end.getTime() - start.getTime();
    time /= 1000;
    Log.w(TAG, "update address book " + mChangeCount++ + " took " + time + " seconds");
    if (identityAdded) {
        //wake up the profile push
        resolver.notifyChange(MusubiService.WHITELIST_APPENDED, this);
    }
    if (profileDataChanged) {
        //refresh the ui...
        resolver.notifyChange(MusubiService.PRIMARY_CONTENT_CHANGED, this);
    }
    if (identityAdded || profileDataChanged) {
        //update the our musubi address book as needed.
        String accountName = mContext.getString(R.string.account_name);
        String accountType = mContext.getString(R.string.account_type);
        Account account = new Account(accountName, accountType);
        ContentResolver.requestSync(account, ContactsContract.AUTHORITY, new Bundle());
    }

    dbManager.close();
    mLastRun = new Date().getTime();
    resolver.notifyChange(MusubiService.ADDRESS_BOOK_SCANNED, this);
}