Search in sources :

Example 1 with StopWatch

use of com.android.contacts.common.util.StopWatch in project android_packages_apps_Dialer by LineageOS.

the class DialerDatabaseHelper method updateSmartDialDatabase.

/**
 * Updates the smart dial and prefix database. This method queries the Delta API to get changed
 * contacts since last update, and updates the records in smartdial database and prefix database
 * accordingly. It also queries the deleted contact database to remove newly deleted contacts
 * since last update.
 */
@WorkerThread
public synchronized void updateSmartDialDatabase() {
    LogUtil.enterBlock("DialerDatabaseHelper.updateSmartDialDatabase");
    final SQLiteDatabase db = getWritableDatabase();
    LogUtil.v("DialerDatabaseHelper.updateSmartDialDatabase", "starting to update database");
    final StopWatch stopWatch = DEBUG ? StopWatch.start("Updating databases") : null;
    /**
     * Gets the last update time on the database.
     */
    final SharedPreferences databaseLastUpdateSharedPref = mContext.getSharedPreferences(DATABASE_LAST_CREATED_SHARED_PREF, Context.MODE_PRIVATE);
    final String lastUpdateMillis = String.valueOf(databaseLastUpdateSharedPref.getLong(LAST_UPDATED_MILLIS, 0));
    LogUtil.v("DialerDatabaseHelper.updateSmartDialDatabase", "last updated at " + lastUpdateMillis);
    /**
     * Sets the time after querying the database as the current update time.
     */
    final Long currentMillis = System.currentTimeMillis();
    if (DEBUG) {
        stopWatch.lap("Queried the Contacts database");
    }
    /**
     * Removes contacts that have been deleted.
     */
    removeDeletedContacts(db, getDeletedContactCursor(lastUpdateMillis));
    removePotentiallyCorruptedContacts(db, lastUpdateMillis);
    if (DEBUG) {
        stopWatch.lap("Finished deleting deleted entries");
    }
    /**
     * If the database did not exist before, jump through deletion as there is nothing to delete.
     */
    if (!lastUpdateMillis.equals("0")) {
        /**
         * Removes contacts that have been updated. Updated contact information will be inserted
         * later. Note that this has to use a separate result set from updatePhoneCursor, since it is
         * possible for a contact to be updated (e.g. phone number deleted), but have no results show
         * up in updatedPhoneCursor (since all of its phone numbers have been deleted).
         */
        final Cursor updatedContactCursor = mContext.getContentResolver().query(UpdatedContactQuery.URI, UpdatedContactQuery.PROJECTION, UpdatedContactQuery.SELECT_UPDATED_CLAUSE, new String[] { lastUpdateMillis }, null);
        if (updatedContactCursor == null) {
            LogUtil.e("DialerDatabaseHelper.updateSmartDialDatabase", "smartDial query received null for cursor");
            return;
        }
        try {
            removeUpdatedContacts(db, updatedContactCursor);
        } finally {
            updatedContactCursor.close();
        }
        if (DEBUG) {
            stopWatch.lap("Finished deleting entries belonging to updated contacts");
        }
    }
    /**
     * Queries the contact database to get all phone numbers that have been updated since the last
     * update time.
     */
    final Cursor updatedPhoneCursor = mContext.getContentResolver().query(PhoneQuery.URI, PhoneQuery.PROJECTION, PhoneQuery.SELECTION, new String[] { lastUpdateMillis }, null);
    if (updatedPhoneCursor == null) {
        LogUtil.e("DialerDatabaseHelper.updateSmartDialDatabase", "smartDial query received null for cursor");
        return;
    }
    try {
        /**
         * Inserts recently updated phone numbers to the smartdial database.
         */
        insertUpdatedContactsAndNumberPrefix(db, updatedPhoneCursor, currentMillis);
        if (DEBUG) {
            stopWatch.lap("Finished building the smart dial table");
        }
    } finally {
        updatedPhoneCursor.close();
    }
    /**
     * Gets a list of distinct contacts which have been updated, and adds the name prefixes of these
     * contacts to the prefix table.
     */
    final Cursor nameCursor = db.rawQuery("SELECT DISTINCT " + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " + SmartDialDbColumns.CONTACT_ID + " FROM " + Tables.SMARTDIAL_TABLE + " WHERE " + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + " = " + currentMillis, new String[] {});
    if (nameCursor != null) {
        try {
            if (DEBUG) {
                stopWatch.lap("Queried the smart dial table for contact names");
            }
            /**
             * Inserts prefixes of names into the prefix table.
             */
            insertNamePrefixes(db, nameCursor);
            if (DEBUG) {
                stopWatch.lap("Finished building the name prefix table");
            }
        } finally {
            nameCursor.close();
        }
    }
    /**
     * Creates index on contact_id for fast JOIN operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_contact_id_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.CONTACT_ID + ");");
    /**
     * Creates index on last_smartdial_update_time for fast SELECT operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_last_update_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + ");");
    /**
     * Creates index on sorting fields for fast sort operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_sort_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.STARRED + ", " + SmartDialDbColumns.IS_SUPER_PRIMARY + ", " + SmartDialDbColumns.LAST_TIME_USED + ", " + SmartDialDbColumns.TIMES_USED + ", " + SmartDialDbColumns.IN_VISIBLE_GROUP + ", " + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " + SmartDialDbColumns.CONTACT_ID + ", " + SmartDialDbColumns.IS_PRIMARY + ");");
    /**
     * Creates index on prefix for fast SELECT operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS nameprefix_index ON " + Tables.PREFIX_TABLE + " (" + PrefixColumns.PREFIX + ");");
    /**
     * Creates index on contact_id for fast JOIN operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS nameprefix_contact_id_index ON " + Tables.PREFIX_TABLE + " (" + PrefixColumns.CONTACT_ID + ");");
    if (DEBUG) {
        stopWatch.lap(TAG + "Finished recreating index");
    }
    /**
     * Updates the database index statistics.
     */
    db.execSQL("ANALYZE " + Tables.SMARTDIAL_TABLE);
    db.execSQL("ANALYZE " + Tables.PREFIX_TABLE);
    db.execSQL("ANALYZE smartdial_contact_id_index");
    db.execSQL("ANALYZE smartdial_last_update_index");
    db.execSQL("ANALYZE nameprefix_index");
    db.execSQL("ANALYZE nameprefix_contact_id_index");
    if (DEBUG) {
        stopWatch.stopAndLog(TAG + "Finished updating index stats", 0);
    }
    final SharedPreferences.Editor editor = databaseLastUpdateSharedPref.edit();
    editor.putLong(LAST_UPDATED_MILLIS, currentMillis);
    editor.apply();
    LogUtil.i("DialerDatabaseHelper.updateSmartDialDatabase", "broadcasting smart dial update");
    // Notify content observers that smart dial database has been updated.
    Intent intent = new Intent(ACTION_SMART_DIAL_UPDATED);
    intent.setPackage(mContext.getPackageName());
    mContext.sendBroadcast(intent);
}
Also used : SQLiteDatabase(android.database.sqlite.SQLiteDatabase) SharedPreferences(android.content.SharedPreferences) Intent(android.content.Intent) Cursor(android.database.Cursor) StopWatch(com.android.contacts.common.util.StopWatch) WorkerThread(android.support.annotation.WorkerThread)

Example 2 with StopWatch

use of com.android.contacts.common.util.StopWatch in project android_packages_apps_Dialer by LineageOS.

the class DialpadFragment method onResume.

@Override
public void onResume() {
    LogUtil.d("DialpadFragment.onResume", "");
    Trace.beginSection(TAG + " onResume");
    super.onResume();
    Resources res = getResources();
    int iconId = R.drawable.quantum_ic_call_vd_theme_24;
    if (MotorolaUtils.isWifiCallingAvailable(getContext())) {
        iconId = R.drawable.ic_wifi_calling;
    }
    mFloatingActionButtonController.changeIcon(res.getDrawable(iconId, null), res.getString(R.string.description_dial_button));
    final DialtactsActivity activity = (DialtactsActivity) getActivity();
    mDialpadQueryListener = activity;
    final StopWatch stopWatch = StopWatch.start("Dialpad.onResume");
    // Query the last dialed number. Do it first because hitting
    // the DB is 'slow'. This call is asynchronous.
    queryLastOutgoingCall();
    stopWatch.lap("qloc");
    final ContentResolver contentResolver = activity.getContentResolver();
    // retrieve the DTMF tone play back setting.
    mDTMFToneEnabled = Settings.System.getInt(contentResolver, Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
    stopWatch.lap("dtwd");
    stopWatch.lap("hptc");
    mPressedDialpadKeys.clear();
    configureScreenFromIntent(getActivity());
    stopWatch.lap("fdin");
    if (!isPhoneInUse()) {
        // A sanity-check: the "dialpad chooser" UI should not be visible if the phone is idle.
        showDialpadChooser(false);
    }
    stopWatch.lap("hnt");
    updateDeleteButtonEnabledState();
    stopWatch.lap("bes");
    stopWatch.stopAndLog(TAG, 50);
    // Populate the overflow menu in onResume instead of onCreate, so that if the SMS activity
    // is disabled while Dialer is paused, the "Send a text message" option can be correctly
    // removed when resumed.
    mOverflowMenuButton = mDialpadView.getOverflowMenuButton();
    mOverflowPopupMenu = buildOptionsMenu(mOverflowMenuButton);
    mOverflowMenuButton.setOnTouchListener(mOverflowPopupMenu.getDragToOpenListener());
    mOverflowMenuButton.setOnClickListener(this);
    mOverflowMenuButton.setVisibility(isDigitsEmpty() ? View.INVISIBLE : View.VISIBLE);
    if (mFirstLaunch) {
        // The onHiddenChanged callback does not get called the first time the fragment is
        // attached, so call it ourselves here.
        onHiddenChanged(false);
    }
    mFirstLaunch = false;
    Trace.endSection();
}
Also used : DialtactsActivity(com.android.dialer.app.DialtactsActivity) Resources(android.content.res.Resources) StopWatch(com.android.contacts.common.util.StopWatch) ContentResolver(android.content.ContentResolver)

Example 3 with StopWatch

use of com.android.contacts.common.util.StopWatch in project android_packages_apps_Dialer by LineageOS.

the class DialerDatabaseHelper method getLooseMatches.

/**
 * Returns a list of candidate contacts where the query is a prefix of the dialpad index of the
 * contact's name or phone number.
 *
 * @param query The prefix of a contact's dialpad index.
 * @return A list of top candidate contacts that will be suggested to user to match their input.
 */
@WorkerThread
public synchronized ArrayList<ContactNumber> getLooseMatches(String query, SmartDialNameMatcher nameMatcher) {
    final SQLiteDatabase db = getReadableDatabase();
    /**
     * Uses SQL query wildcard '%' to represent prefix matching.
     */
    final String looseQuery = query + "%";
    final ArrayList<ContactNumber> result = new ArrayList<>();
    final StopWatch stopWatch = DEBUG ? StopWatch.start(":Name Prefix query") : null;
    final String currentTimeStamp = Long.toString(System.currentTimeMillis());
    /**
     * Queries the database to find contacts that have an index matching the query prefix.
     */
    final Cursor cursor = db.rawQuery("SELECT " + SmartDialDbColumns.DATA_ID + ", " + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " + SmartDialDbColumns.PHOTO_ID + ", " + SmartDialDbColumns.NUMBER + ", " + SmartDialDbColumns.CONTACT_ID + ", " + SmartDialDbColumns.LOOKUP_KEY + ", " + SmartDialDbColumns.CARRIER_PRESENCE + " FROM " + Tables.SMARTDIAL_TABLE + " WHERE " + SmartDialDbColumns.CONTACT_ID + " IN " + " (SELECT " + PrefixColumns.CONTACT_ID + " FROM " + Tables.PREFIX_TABLE + " WHERE " + Tables.PREFIX_TABLE + "." + PrefixColumns.PREFIX + " LIKE '" + looseQuery + "')" + " ORDER BY " + SmartDialSortingOrder.SORT_ORDER, new String[] { currentTimeStamp });
    if (cursor == null) {
        return result;
    }
    try {
        if (DEBUG) {
            stopWatch.lap("Prefix query completed");
        }
        /**
         * Gets the column ID from the cursor.
         */
        final int columnDataId = 0;
        final int columnDisplayNamePrimary = 1;
        final int columnPhotoId = 2;
        final int columnNumber = 3;
        final int columnId = 4;
        final int columnLookupKey = 5;
        final int columnCarrierPresence = 6;
        if (DEBUG) {
            stopWatch.lap("Found column IDs");
        }
        final Set<ContactMatch> duplicates = new HashSet<>();
        int counter = 0;
        if (DEBUG) {
            stopWatch.lap("Moved cursor to start");
        }
        /**
         * Iterates the cursor to find top contact suggestions without duplication.
         */
        while ((cursor.moveToNext()) && (counter < MAX_ENTRIES)) {
            if (cursor.isNull(columnDataId)) {
                LogUtil.i("DialerDatabaseHelper.getLooseMatches", "_id column null. Row was deleted during iteration, skipping");
                continue;
            }
            final long dataID = cursor.getLong(columnDataId);
            final String displayName = cursor.getString(columnDisplayNamePrimary);
            final String phoneNumber = cursor.getString(columnNumber);
            final long id = cursor.getLong(columnId);
            final long photoId = cursor.getLong(columnPhotoId);
            final String lookupKey = cursor.getString(columnLookupKey);
            final int carrierPresence = cursor.getInt(columnCarrierPresence);
            /**
             * If a contact already exists and another phone number of the contact is being processed,
             * skip the second instance.
             */
            final ContactMatch contactMatch = new ContactMatch(lookupKey, id);
            if (duplicates.contains(contactMatch)) {
                continue;
            }
            /**
             * If the contact has either the name or number that matches the query, add to the result.
             */
            final boolean nameMatches = nameMatcher.matches(context, displayName);
            final boolean numberMatches = (nameMatcher.matchesNumber(context, phoneNumber, query) != null);
            if (nameMatches || numberMatches) {
                /**
                 * If a contact has not been added, add it to the result and the hash set.
                 */
                duplicates.add(contactMatch);
                result.add(new ContactNumber(id, dataID, displayName, phoneNumber, lookupKey, photoId, carrierPresence));
                counter++;
                if (DEBUG) {
                    stopWatch.lap("Added one result: Name: " + displayName);
                }
            }
        }
        if (DEBUG) {
            stopWatch.stopAndLog(TAG + "Finished loading cursor", 0);
        }
    } finally {
        cursor.close();
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) StopWatch(com.android.contacts.common.util.StopWatch) SQLiteDatabase(android.database.sqlite.SQLiteDatabase) HashSet(java.util.HashSet) WorkerThread(android.support.annotation.WorkerThread)

Example 4 with StopWatch

use of com.android.contacts.common.util.StopWatch in project android_packages_apps_Dialer by LineageOS.

the class DialerDatabaseHelper method updateSmartDialDatabase.

/**
 * Updates the smart dial and prefix database. This method queries the Delta API to get changed
 * contacts since last update, and updates the records in smartdial database and prefix database
 * accordingly. It also queries the deleted contact database to remove newly deleted contacts
 * since last update.
 *
 * @param forceUpdate If set to true, update the database by reloading all contacts.
 */
@WorkerThread
public void updateSmartDialDatabase(boolean forceUpdate) {
    LogUtil.enterBlock("DialerDatabaseHelper.updateSmartDialDatabase");
    final SQLiteDatabase db = getWritableDatabase();
    LogUtil.v("DialerDatabaseHelper.updateSmartDialDatabase", "starting to update database");
    final StopWatch stopWatch = DEBUG ? StopWatch.start("Updating databases") : null;
    /**
     * Gets the last update time on the database.
     */
    final SharedPreferences databaseLastUpdateSharedPref = context.getSharedPreferences(DATABASE_LAST_CREATED_SHARED_PREF, Context.MODE_PRIVATE);
    long defaultLastUpdateMillis = ConfigProviderComponent.get(context).getConfigProvider().getLong(DEFAULT_LAST_UPDATED_CONFIG_KEY, 0);
    long sharedPrefLastUpdateMillis = databaseLastUpdateSharedPref.getLong(LAST_UPDATED_MILLIS, defaultLastUpdateMillis);
    final String lastUpdateMillis = String.valueOf(forceUpdate ? 0 : sharedPrefLastUpdateMillis);
    LogUtil.i("DialerDatabaseHelper.updateSmartDialDatabase", "last updated at %s", lastUpdateMillis);
    /**
     * Sets the time after querying the database as the current update time.
     */
    final Long currentMillis = System.currentTimeMillis();
    if (DEBUG) {
        stopWatch.lap("Queried the Contacts database");
    }
    /**
     * Removes contacts that have been deleted.
     */
    removeDeletedContacts(db, lastUpdateMillis);
    removePotentiallyCorruptedContacts(db, lastUpdateMillis);
    if (DEBUG) {
        stopWatch.lap("Finished deleting deleted entries");
    }
    /**
     * If the database did not exist before, jump through deletion as there is nothing to delete.
     */
    if (!lastUpdateMillis.equals("0")) {
        /**
         * Removes contacts that have been updated. Updated contact information will be inserted
         * later. Note that this has to use a separate result set from updatePhoneCursor, since it is
         * possible for a contact to be updated (e.g. phone number deleted), but have no results show
         * up in updatedPhoneCursor (since all of its phone numbers have been deleted).
         */
        final Cursor updatedContactCursor = context.getContentResolver().query(UpdatedContactQuery.URI, UpdatedContactQuery.PROJECTION, UpdatedContactQuery.SELECT_UPDATED_CLAUSE, new String[] { lastUpdateMillis }, null);
        if (updatedContactCursor == null) {
            LogUtil.e("DialerDatabaseHelper.updateSmartDialDatabase", "smartDial query received null for cursor");
            return;
        }
        try {
            removeUpdatedContacts(db, updatedContactCursor);
        } finally {
            updatedContactCursor.close();
        }
        if (DEBUG) {
            stopWatch.lap("Finished deleting entries belonging to updated contacts");
        }
    }
    /**
     * Queries the contact database to get all phone numbers that have been updated since the last
     * update time.
     */
    final Cursor updatedPhoneCursor = context.getContentResolver().query(PhoneQuery.URI, PhoneQuery.PROJECTION, PhoneQuery.SELECTION, new String[] { lastUpdateMillis }, null);
    if (updatedPhoneCursor == null) {
        LogUtil.e("DialerDatabaseHelper.updateSmartDialDatabase", "smartDial query received null for cursor");
        return;
    }
    try {
        /**
         * Inserts recently updated phone numbers to the smartdial database.
         */
        insertUpdatedContactsAndNumberPrefix(db, updatedPhoneCursor, currentMillis);
        if (DEBUG) {
            stopWatch.lap("Finished building the smart dial table");
        }
    } finally {
        updatedPhoneCursor.close();
    }
    /**
     * Gets a list of distinct contacts which have been updated, and adds the name prefixes of these
     * contacts to the prefix table.
     */
    final Cursor nameCursor = db.rawQuery("SELECT DISTINCT " + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " + SmartDialDbColumns.CONTACT_ID + " FROM " + Tables.SMARTDIAL_TABLE + " WHERE " + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + " = " + currentMillis, new String[] {});
    if (nameCursor != null) {
        try {
            if (DEBUG) {
                stopWatch.lap("Queried the smart dial table for contact names");
            }
            /**
             * Inserts prefixes of names into the prefix table.
             */
            insertNamePrefixes(db, nameCursor);
            if (DEBUG) {
                stopWatch.lap("Finished building the name prefix table");
            }
        } finally {
            nameCursor.close();
        }
    }
    /**
     * Creates index on contact_id for fast JOIN operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_contact_id_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.CONTACT_ID + ");");
    /**
     * Creates index on last_smartdial_update_time for fast SELECT operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_last_update_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + ");");
    /**
     * Creates index on sorting fields for fast sort operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_sort_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.STARRED + ", " + SmartDialDbColumns.IS_SUPER_PRIMARY + ", " + SmartDialDbColumns.LAST_TIME_USED + ", " + SmartDialDbColumns.TIMES_USED + ", " + SmartDialDbColumns.IN_VISIBLE_GROUP + ", " + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " + SmartDialDbColumns.CONTACT_ID + ", " + SmartDialDbColumns.IS_PRIMARY + ");");
    /**
     * Creates index on prefix for fast SELECT operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS nameprefix_index ON " + Tables.PREFIX_TABLE + " (" + PrefixColumns.PREFIX + ");");
    /**
     * Creates index on contact_id for fast JOIN operation.
     */
    db.execSQL("CREATE INDEX IF NOT EXISTS nameprefix_contact_id_index ON " + Tables.PREFIX_TABLE + " (" + PrefixColumns.CONTACT_ID + ");");
    if (DEBUG) {
        stopWatch.lap(TAG + "Finished recreating index");
    }
    /**
     * Updates the database index statistics.
     */
    db.execSQL("ANALYZE " + Tables.SMARTDIAL_TABLE);
    db.execSQL("ANALYZE " + Tables.PREFIX_TABLE);
    db.execSQL("ANALYZE smartdial_contact_id_index");
    db.execSQL("ANALYZE smartdial_last_update_index");
    db.execSQL("ANALYZE nameprefix_index");
    db.execSQL("ANALYZE nameprefix_contact_id_index");
    if (DEBUG) {
        stopWatch.stopAndLog(TAG + "Finished updating index stats", 0);
    }
    final SharedPreferences.Editor editor = databaseLastUpdateSharedPref.edit();
    editor.putLong(LAST_UPDATED_MILLIS, currentMillis);
    editor.apply();
    LogUtil.i("DialerDatabaseHelper.updateSmartDialDatabase", "broadcasting smart dial update");
    // Notify content observers that smart dial database has been updated.
    Intent intent = new Intent(ACTION_SMART_DIAL_UPDATED);
    intent.setPackage(context.getPackageName());
    context.sendBroadcast(intent);
}
Also used : SQLiteDatabase(android.database.sqlite.SQLiteDatabase) SharedPreferences(android.content.SharedPreferences) Intent(android.content.Intent) Cursor(android.database.Cursor) StopWatch(com.android.contacts.common.util.StopWatch) WorkerThread(android.support.annotation.WorkerThread)

Example 5 with StopWatch

use of com.android.contacts.common.util.StopWatch in project android_packages_apps_Dialer by MoKee.

the class DialerDatabaseHelper method updateSmartDialDatabase.

/**
 * Updates the smart dial and prefix database.
 * This method queries the Delta API to get changed contacts since last update, and updates the
 * records in smartdial database and prefix database accordingly.
 * It also queries the deleted contact database to remove newly deleted contacts since last
 * update.
 */
public void updateSmartDialDatabase() {
    initMultiLanguageSearch();
    final SQLiteDatabase db = getWritableDatabase();
    synchronized (mLock) {
        if (DEBUG) {
            Log.v(TAG, "Starting to update database");
        }
        final StopWatch stopWatch = DEBUG ? StopWatch.start("Updating databases") : null;
        /**
         * Gets the last update time on the database.
         */
        final SharedPreferences databaseLastUpdateSharedPref = mContext.getSharedPreferences(DATABASE_LAST_CREATED_SHARED_PREF, Context.MODE_PRIVATE);
        final String lastUpdateMillis = String.valueOf(databaseLastUpdateSharedPref.getLong(LAST_UPDATED_MILLIS, 0));
        if (DEBUG) {
            Log.v(TAG, "Last updated at " + lastUpdateMillis);
        }
        /**
         * Sets the time after querying the database as the current update time.
         */
        final Long currentMillis = System.currentTimeMillis();
        if (DEBUG) {
            stopWatch.lap("Queried the Contacts database");
        }
        /**
         * Prevents the app from reading the dialer database when updating.
         */
        sInUpdate.getAndSet(true);
        /**
         * Removes contacts that have been deleted.
         */
        removeDeletedContacts(db, getDeletedContactCursor(lastUpdateMillis));
        removePotentiallyCorruptedContacts(db, lastUpdateMillis);
        if (DEBUG) {
            stopWatch.lap("Finished deleting deleted entries");
        }
        /**
         * If the database did not exist before, jump through deletion as there is nothing
         * to delete.
         */
        if (!lastUpdateMillis.equals("0")) {
            /**
             * Removes contacts that have been updated. Updated contact information will be
             * inserted later. Note that this has to use a separate result set from
             * updatePhoneCursor, since it is possible for a contact to be updated (e.g.
             * phone number deleted), but have no results show up in updatedPhoneCursor (since
             * all of its phone numbers have been deleted).
             */
            final Cursor updatedContactCursor = mContext.getContentResolver().query(UpdatedContactQuery.URI, UpdatedContactQuery.PROJECTION, UpdatedContactQuery.SELECT_UPDATED_CLAUSE, new String[] { lastUpdateMillis }, null);
            if (updatedContactCursor == null) {
                Log.e(TAG, "SmartDial query received null for cursor");
                return;
            }
            try {
                removeUpdatedContacts(db, updatedContactCursor);
            } finally {
                updatedContactCursor.close();
            }
            if (DEBUG) {
                stopWatch.lap("Finished deleting entries belonging to updated contacts");
            }
        }
        /**
         * Queries the contact database to get all phone numbers that have been updated since the last
         * update time.
         */
        final Cursor updatedPhoneCursor = mContext.getContentResolver().query(PhoneQuery.URI, PhoneQuery.PROJECTION, PhoneQuery.SELECTION, new String[] { lastUpdateMillis }, null);
        if (updatedPhoneCursor == null) {
            Log.e(TAG, "SmartDial query received null for cursor");
            return;
        }
        try {
            /**
             * Inserts recently updated phone numbers to the smartdial database.
             */
            insertUpdatedContactsAndNumberPrefix(db, updatedPhoneCursor, currentMillis);
            if (DEBUG) {
                stopWatch.lap("Finished building the smart dial table");
            }
        } finally {
            updatedPhoneCursor.close();
        }
        /**
         * Gets a list of distinct contacts which have been updated, and adds the name prefixes
         * of these contacts to the prefix table.
         */
        final Cursor nameCursor = db.rawQuery("SELECT DISTINCT " + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " + SmartDialDbColumns.CONTACT_ID + " FROM " + Tables.SMARTDIAL_TABLE + " WHERE " + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + " = " + Long.toString(currentMillis), new String[] {});
        if (nameCursor != null) {
            try {
                if (DEBUG) {
                    stopWatch.lap("Queried the smart dial table for contact names");
                }
                /**
                 * Inserts prefixes of names into the prefix table.
                 */
                insertNamePrefixes(db, nameCursor);
                if (DEBUG) {
                    stopWatch.lap("Finished building the name prefix table");
                }
            } finally {
                nameCursor.close();
            }
        }
        /**
         * Creates index on contact_id for fast JOIN operation.
         */
        db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_contact_id_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.CONTACT_ID + ");");
        /**
         * Creates index on last_smartdial_update_time for fast SELECT operation.
         */
        db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_last_update_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + ");");
        /**
         * Creates index on sorting fields for fast sort operation.
         */
        db.execSQL("CREATE INDEX IF NOT EXISTS smartdial_sort_index ON " + Tables.SMARTDIAL_TABLE + " (" + SmartDialDbColumns.STARRED + ", " + SmartDialDbColumns.IS_SUPER_PRIMARY + ", " + SmartDialDbColumns.LAST_TIME_USED + ", " + SmartDialDbColumns.TIMES_USED + ", " + SmartDialDbColumns.IN_VISIBLE_GROUP + ", " + SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " + SmartDialDbColumns.CONTACT_ID + ", " + SmartDialDbColumns.IS_PRIMARY + ");");
        /**
         * Creates index on prefix for fast SELECT operation.
         */
        db.execSQL("CREATE INDEX IF NOT EXISTS nameprefix_index ON " + Tables.PREFIX_TABLE + " (" + PrefixColumns.PREFIX + ");");
        /**
         * Creates index on contact_id for fast JOIN operation.
         */
        db.execSQL("CREATE INDEX IF NOT EXISTS nameprefix_contact_id_index ON " + Tables.PREFIX_TABLE + " (" + PrefixColumns.CONTACT_ID + ");");
        if (DEBUG) {
            stopWatch.lap(TAG + "Finished recreating index");
        }
        /**
         * Updates the database index statistics.
         */
        db.execSQL("ANALYZE " + Tables.SMARTDIAL_TABLE);
        db.execSQL("ANALYZE " + Tables.PREFIX_TABLE);
        db.execSQL("ANALYZE smartdial_contact_id_index");
        db.execSQL("ANALYZE smartdial_last_update_index");
        db.execSQL("ANALYZE nameprefix_index");
        db.execSQL("ANALYZE nameprefix_contact_id_index");
        if (DEBUG) {
            stopWatch.stopAndLog(TAG + "Finished updating index stats", 0);
        }
        sInUpdate.getAndSet(false);
        final SharedPreferences.Editor editor = databaseLastUpdateSharedPref.edit();
        editor.putLong(LAST_UPDATED_MILLIS, currentMillis);
        editor.commit();
        // Notify content observers that smart dial database has been updated.
        mContext.getContentResolver().notifyChange(SMART_DIAL_UPDATED_URI, null, false);
    }
}
Also used : SQLiteDatabase(android.database.sqlite.SQLiteDatabase) SharedPreferences(android.content.SharedPreferences) Cursor(android.database.Cursor) StopWatch(com.android.contacts.common.util.StopWatch)

Aggregations

StopWatch (com.android.contacts.common.util.StopWatch)10 Cursor (android.database.Cursor)6 SQLiteDatabase (android.database.sqlite.SQLiteDatabase)6 WorkerThread (android.support.annotation.WorkerThread)5 ContentResolver (android.content.ContentResolver)4 Intent (android.content.Intent)4 SharedPreferences (android.content.SharedPreferences)4 Resources (android.content.res.Resources)2 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 BroadcastReceiver (android.content.BroadcastReceiver)1 Context (android.content.Context)1 IntentFilter (android.content.IntentFilter)1 DialtactsActivity (com.android.dialer.DialtactsActivity)1 DialtactsActivity (com.android.dialer.app.DialtactsActivity)1