blob: 7efc8910485691ee3f094dc00feb8b667b63403d [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.providers.contacts;
import com.android.internal.annotations.VisibleForTesting;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
/**
* Helper class for PHONE_LOOKUP's that involve numbers with "*" prefixes.
*/
/* package-protected */ final class PhoneLookupWithStarPrefix {
private static final String TAG = "PhoneLookupWSP";
/**
* Returns a cursor with a subset of the rows passed into this function. If {@param number}
* starts with a "*" then only rows from {@param cursor} that have a number equal to
* {@param number} will be returned. If {@param number} doesn't start with a "*", then
* only rows from {@param cursor} that have numbers without starting "*" characters
* will be returned.
*
* This function is used to resolve b/13195334.
*
* @param number unnormalized phone number.
* @param cursor this function takes ownership of the cursor. The calling scope MUST NOT
* use or close() the cursor passed into this function. The cursor must contain
* PhoneLookup.NUMBER.
*
* @return a cursor that the calling context owns
*/
public static Cursor removeNonStarMatchesFromCursor(String number, Cursor cursor) {
// Close cursors that we don't return.
Cursor unreturnedCursor = cursor;
try {
if (TextUtils.isEmpty(number)) {
unreturnedCursor = null;
return cursor;
}
final String queryPhoneNumberNormalized = normalizeNumberWithStar(number);
if (!queryPhoneNumberNormalized.startsWith("*")
&& !matchingNumberStartsWithStar(cursor)) {
cursor.moveToPosition(-1);
unreturnedCursor = null;
return cursor;
}
final MatrixCursor matrixCursor = new MatrixCursor(cursor.getColumnNames());
// Close cursors that we don't return.
Cursor unreturnedMatrixCursor = matrixCursor;
try {
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
final int numberIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
final String matchingNumberNormalized
= normalizeNumberWithStar(cursor.getString(numberIndex));
if (!matchingNumberNormalized.startsWith("*")
&& !queryPhoneNumberNormalized.startsWith("*")
|| matchingNumberNormalized.equals(queryPhoneNumberNormalized)) {
// Copy row from cursor into matrixCursor
final MatrixCursor.RowBuilder b = matrixCursor.newRow();
for (int column = 0; column < cursor.getColumnCount(); column++) {
b.add(cursor.getColumnName(column), cursorValue(cursor, column));
}
}
}
unreturnedMatrixCursor = null;
return matrixCursor;
} finally {
if (unreturnedMatrixCursor != null) {
unreturnedMatrixCursor.close();
}
}
} finally {
if (unreturnedCursor != null) {
unreturnedCursor.close();
}
}
}
@VisibleForTesting
static String normalizeNumberWithStar(String phoneNumber) {
if (TextUtils.isEmpty(phoneNumber)) {
return phoneNumber;
}
if (phoneNumber.startsWith("*")) {
// Use PhoneNumberUtils.normalizeNumber() to normalize the rest of the number after
// the leading "*". Strip out the "+" since "+"s are only allowed as leading
// characters. NOTE: This statement has poor performance. Fortunately, it won't be
// called very often.
return "*" + PhoneNumberUtils.normalizeNumber(
phoneNumber.substring(1).replace("+", ""));
}
return PhoneNumberUtils.normalizeNumber(phoneNumber);
}
/**
* @return whether {@param cursor} contain any numbers that start with "*"
*/
private static boolean matchingNumberStartsWithStar(Cursor cursor) {
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
final int numberIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
final String phoneNumber = normalizeNumberWithStar(cursor.getString(numberIndex));
if (phoneNumber != null && phoneNumber.startsWith("*")) {
return true;
}
}
return false;
}
private static Object cursorValue(Cursor cursor, int column) {
switch(cursor.getType(column)) {
case Cursor.FIELD_TYPE_BLOB:
return cursor.getBlob(column);
case Cursor.FIELD_TYPE_INTEGER:
return cursor.getInt(column);
case Cursor.FIELD_TYPE_FLOAT:
return cursor.getFloat(column);
case Cursor.FIELD_TYPE_STRING:
return cursor.getString(column);
case Cursor.FIELD_TYPE_NULL:
return null;
default:
Log.d(TAG, "Invalid value in cursor: " + cursor.getType(column));
return null;
}
}
}