Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.dialer.searchfragment.common;
     18 
     19 import android.support.annotation.NonNull;
     20 import android.telephony.PhoneNumberUtils;
     21 import android.text.TextUtils;
     22 import java.util.regex.Pattern;
     23 
     24 /** Utility class for filtering, comparing and handling strings and queries. */
     25 public class QueryFilteringUtil {
     26 
     27   /** Matches strings with "-", "(", ")", 2-9 of at least length one. */
     28   static final Pattern T9_PATTERN = Pattern.compile("[\\-()2-9]+");
     29 
     30   /**
     31    * @return true if the query is of T9 format and the name's T9 representation belongs to the
     32    *     query; false otherwise.
     33    */
     34   public static boolean nameMatchesT9Query(String query, String name) {
     35     if (!T9_PATTERN.matcher(query).matches()) {
     36       return false;
     37     }
     38 
     39     // Substring
     40     if (indexOfQueryNonDigitsIgnored(query, getT9Representation(name)) != -1) {
     41       return true;
     42     }
     43 
     44     // Check matches initials
     45     // TODO investigate faster implementation
     46     query = digitsOnly(query);
     47     int queryIndex = 0;
     48 
     49     String[] names = name.toLowerCase().split("\\s");
     50     for (int i = 0; i < names.length && queryIndex < query.length(); i++) {
     51       if (TextUtils.isEmpty(names[i])) {
     52         continue;
     53       }
     54 
     55       if (getDigit(names[i].charAt(0)) == query.charAt(queryIndex)) {
     56         queryIndex++;
     57       }
     58     }
     59 
     60     return queryIndex == query.length();
     61   }
     62 
     63   /** @return true if the number belongs to the query. */
     64   public static boolean numberMatchesNumberQuery(String query, String number) {
     65     return PhoneNumberUtils.isGlobalPhoneNumber(query)
     66         && indexOfQueryNonDigitsIgnored(query, number) != -1;
     67   }
     68 
     69   /**
     70    * Checks if query is contained in number while ignoring all characters in both that are not
     71    * digits (i.e. {@link Character#isDigit(char)} returns false).
     72    *
     73    * @return index where query is found with all non-digits removed, -1 if it's not found.
     74    */
     75   static int indexOfQueryNonDigitsIgnored(@NonNull String query, @NonNull String number) {
     76     return digitsOnly(number).indexOf(digitsOnly(query));
     77   }
     78 
     79   // Returns string with letters replaced with their T9 representation.
     80   static String getT9Representation(String s) {
     81     StringBuilder builder = new StringBuilder(s.length());
     82     for (char c : s.toLowerCase().toCharArray()) {
     83       builder.append(getDigit(c));
     84     }
     85     return builder.toString();
     86   }
     87 
     88   /** @return String s with only digits recognized by Character#isDigit() remaining */
     89   public static String digitsOnly(String s) {
     90     StringBuilder sb = new StringBuilder();
     91     for (int i = 0; i < s.length(); i++) {
     92       char c = s.charAt(i);
     93       if (Character.isDigit(c)) {
     94         sb.append(c);
     95       }
     96     }
     97     return sb.toString();
     98   }
     99 
    100   // Returns the T9 representation of a lower case character, otherwise returns the character.
    101   static char getDigit(char c) {
    102     switch (c) {
    103       case 'a':
    104       case 'b':
    105       case 'c':
    106         return '2';
    107       case 'd':
    108       case 'e':
    109       case 'f':
    110         return '3';
    111       case 'g':
    112       case 'h':
    113       case 'i':
    114         return '4';
    115       case 'j':
    116       case 'k':
    117       case 'l':
    118         return '5';
    119       case 'm':
    120       case 'n':
    121       case 'o':
    122         return '6';
    123       case 'p':
    124       case 'q':
    125       case 'r':
    126       case 's':
    127         return '7';
    128       case 't':
    129       case 'u':
    130       case 'v':
    131         return '8';
    132       case 'w':
    133       case 'x':
    134       case 'y':
    135       case 'z':
    136         return '9';
    137       default:
    138         return c;
    139     }
    140   }
    141 }
    142