/**
   * Configures the query string to be used to find SmartDial matches.
   *
   * @param query The query string user typed.
   */
  public void configureQuery(String query, boolean isSmartQuery) {

    LogUtils.d(TAG, "MTK-DialerSearch, Configure new query to be " + query);

    if (isSmartQuery) {
      mQuery = SmartDialNameMatcher.normalizeNumber(query, SmartDialPrefix.getMap());
    } else {
      mQuery = query;
      if (DialerSearchUtils.isInValidDialpadString(mQuery)) {
        mRegularSearch = true;
      }
    }
    mContactsPrefs = new ContactsPreferences(mContext);
  }
 @Override
 public void onDialpadQueryChanged(String query) {
   final String normalizedQuery =
       SmartDialNameMatcher.normalizeNumber(query, SmartDialNameMatcher.LATIN_SMART_DIAL_MAP);
   if (!TextUtils.equals(mSearchView.getText(), normalizedQuery)) {
     if (DEBUG) {
       Log.d(TAG, "onDialpadQueryChanged - new query: " + query);
     }
     if (mDialpadFragment == null || !mDialpadFragment.isVisible()) {
       // This callback can happen if the dialpad fragment is recreated because of
       // activity destruction. In that case, don't update the search view because
       // that would bring the user back to the search fragment regardless of the
       // previous state of the application. Instead, just return here and let the
       // fragment manager correctly figure out whatever fragment was last displayed.
       return;
     }
     mSearchView.setText(normalizedQuery);
   }
 }
  /**
   * 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.
   */
  public ArrayList<ContactNumber> getLooseMatches(String query, SmartDialNameMatcher nameMatcher) {
    final boolean inUpdate = sInUpdate.get();
    if (inUpdate) {
      return Lists.newArrayList();
    }

    final SQLiteDatabase db = getReadableDatabase();

    /** Uses SQL query wildcard '%' to represent prefix matching. */
    final String looseQuery = query + "%";

    final ArrayList<ContactNumber> result = Lists.newArrayList();

    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
                + " 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 (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;
    if (DEBUG) {
      stopWatch.lap("Found column IDs");
    }

    final Set<ContactMatch> duplicates = new HashSet<ContactMatch>();
    int counter = 0;
    try {
      if (DEBUG) {
        stopWatch.lap("Moved cursor to start");
      }
      /** Iterates the cursor to find top contact suggestions without duplication. */
      while ((cursor.moveToNext()) && (counter < MAX_ENTRIES)) {
        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);

        /**
         * 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(displayName);
        final boolean numberMatches = (nameMatcher.matchesNumber(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));
          counter++;
          if (DEBUG) {
            stopWatch.lap("Added one result");
          }
        }
      }

      if (DEBUG) {
        stopWatch.stopAndLog(TAG + "Finished loading cursor", 0);
      }
    } finally {
      cursor.close();
    }
    return result;
  }