blob: b80f759d0d6e04858864cf27ab343236c76e0cf5 [file] [log] [blame]
/*
* Copyright (C) 2010 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 android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.FullNameStyle;
import android.provider.ContactsContract.PhoneticNameStyle;
import android.text.TextUtils;
import com.android.providers.contacts.SearchIndexManager.IndexBuilder;
import com.android.providers.contacts.aggregation.AbstractContactAggregator;
/**
* Handler for email address data rows.
*/
public class DataRowHandlerForStructuredName extends DataRowHandler {
private final NameSplitter mSplitter;
private final NameLookupBuilder mNameLookupBuilder;
private final StringBuilder mSb = new StringBuilder();
public DataRowHandlerForStructuredName(Context context, ContactsDatabaseHelper dbHelper,
AbstractContactAggregator aggregator, NameSplitter splitter,
NameLookupBuilder nameLookupBuilder) {
super(context, dbHelper, aggregator, StructuredName.CONTENT_ITEM_TYPE);
mSplitter = splitter;
mNameLookupBuilder = nameLookupBuilder;
}
@Override
public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
ContentValues values) {
fixStructuredNameComponents(values, values);
long dataId = super.insert(db, txContext, rawContactId, values);
String name = values.getAsString(StructuredName.DISPLAY_NAME);
Integer fullNameStyle = values.getAsInteger(StructuredName.FULL_NAME_STYLE);
mNameLookupBuilder.insertNameLookup(rawContactId, dataId, name,
fullNameStyle != null
? mSplitter.getAdjustedFullNameStyle(fullNameStyle)
: FullNameStyle.UNDEFINED);
fixRawContactDisplayName(db, txContext, rawContactId);
triggerAggregation(txContext, rawContactId);
return dataId;
}
@Override
public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
Cursor c, boolean callerIsSyncAdapter, boolean callerIsMetadataSyncAdapter) {
final long dataId = c.getLong(DataUpdateQuery._ID);
final long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
final ContentValues augmented = getAugmentedValues(db, dataId, values);
if (augmented == null) { // No change
return false;
}
fixStructuredNameComponents(augmented, values);
super.update(db, txContext, values, c, callerIsSyncAdapter, callerIsMetadataSyncAdapter);
if (values.containsKey(StructuredName.DISPLAY_NAME)) {
augmented.putAll(values);
String name = augmented.getAsString(StructuredName.DISPLAY_NAME);
mDbHelper.deleteNameLookup(dataId);
Integer fullNameStyle = augmented.getAsInteger(StructuredName.FULL_NAME_STYLE);
mNameLookupBuilder.insertNameLookup(rawContactId, dataId, name,
fullNameStyle != null
? mSplitter.getAdjustedFullNameStyle(fullNameStyle)
: FullNameStyle.UNDEFINED);
}
fixRawContactDisplayName(db, txContext, rawContactId);
triggerAggregation(txContext, rawContactId);
return true;
}
@Override
public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
long dataId = c.getLong(DataDeleteQuery._ID);
long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
int count = super.delete(db, txContext, c);
mDbHelper.deleteNameLookup(dataId);
fixRawContactDisplayName(db, txContext, rawContactId);
triggerAggregation(txContext, rawContactId);
return count;
}
/**
* Specific list of structured fields.
*/
private final String[] STRUCTURED_FIELDS = new String[] {
StructuredName.PREFIX, StructuredName.GIVEN_NAME, StructuredName.MIDDLE_NAME,
StructuredName.FAMILY_NAME, StructuredName.SUFFIX
};
/**
* Parses the supplied display name, but only if the incoming values do
* not already contain structured name parts. Also, if the display name
* is not provided, generate one by concatenating first name and last
* name.
*/
public void fixStructuredNameComponents(ContentValues augmented, ContentValues update) {
final String unstruct = update.getAsString(StructuredName.DISPLAY_NAME);
final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
if (touchedUnstruct && !touchedStruct) {
NameSplitter.Name name = new NameSplitter.Name();
mSplitter.split(name, unstruct);
name.toValues(update);
} else if (!touchedUnstruct
&& (touchedStruct || areAnySpecified(update, STRUCTURED_FIELDS))) {
// We need to update the display name when any structured components
// are specified, even when they are null, which is why we are checking
// areAnySpecified. The touchedStruct in the condition is an optimization:
// if there are non-null values, we know for a fact that some values are present.
NameSplitter.Name name = new NameSplitter.Name();
name.fromValues(augmented);
// As the name could be changed, let's guess the name style again.
name.fullNameStyle = FullNameStyle.UNDEFINED;
name.phoneticNameStyle = PhoneticNameStyle.UNDEFINED;
mSplitter.guessNameStyle(name);
int unadjustedFullNameStyle = name.fullNameStyle;
name.fullNameStyle = mSplitter.getAdjustedFullNameStyle(name.fullNameStyle);
final String joined = mSplitter.join(name, true, true);
update.put(StructuredName.DISPLAY_NAME, joined);
update.put(StructuredName.FULL_NAME_STYLE, unadjustedFullNameStyle);
update.put(StructuredName.PHONETIC_NAME_STYLE, name.phoneticNameStyle);
} else if (touchedUnstruct && touchedStruct){
if (!update.containsKey(StructuredName.FULL_NAME_STYLE)) {
update.put(StructuredName.FULL_NAME_STYLE,
mSplitter.guessFullNameStyle(unstruct));
}
if (!update.containsKey(StructuredName.PHONETIC_NAME_STYLE)) {
NameSplitter.Name name = new NameSplitter.Name();
name.fromValues(update);
name.phoneticNameStyle = PhoneticNameStyle.UNDEFINED;
mSplitter.guessNameStyle(name);
update.put(StructuredName.PHONETIC_NAME_STYLE, name.phoneticNameStyle);
}
}
}
@Override
public boolean hasSearchableData() {
return true;
}
@Override
public boolean containsSearchableColumns(ContentValues values) {
return values.containsKey(StructuredName.FAMILY_NAME)
|| values.containsKey(StructuredName.GIVEN_NAME)
|| values.containsKey(StructuredName.MIDDLE_NAME)
|| values.containsKey(StructuredName.PHONETIC_FAMILY_NAME)
|| values.containsKey(StructuredName.PHONETIC_GIVEN_NAME)
|| values.containsKey(StructuredName.PHONETIC_MIDDLE_NAME)
|| values.containsKey(StructuredName.PREFIX)
|| values.containsKey(StructuredName.SUFFIX);
}
@Override
public void appendSearchableData(IndexBuilder builder) {
String name = builder.getString(StructuredName.DISPLAY_NAME);
Integer fullNameStyle = builder.getInt(StructuredName.FULL_NAME_STYLE);
mNameLookupBuilder.appendToSearchIndex(builder, name, fullNameStyle != null
? mSplitter.getAdjustedFullNameStyle(fullNameStyle)
: FullNameStyle.UNDEFINED);
String phoneticFamily = builder.getString(StructuredName.PHONETIC_FAMILY_NAME);
String phoneticMiddle = builder.getString(StructuredName.PHONETIC_MIDDLE_NAME);
String phoneticGiven = builder.getString(StructuredName.PHONETIC_GIVEN_NAME);
// Phonetic name is often spelled without spaces
if (!TextUtils.isEmpty(phoneticFamily) || !TextUtils.isEmpty(phoneticMiddle)
|| !TextUtils.isEmpty(phoneticGiven)) {
mSb.setLength(0);
if (!TextUtils.isEmpty(phoneticFamily)) {
builder.appendName(phoneticFamily);
mSb.append(phoneticFamily);
}
if (!TextUtils.isEmpty(phoneticMiddle)) {
builder.appendName(phoneticMiddle);
mSb.append(phoneticMiddle);
}
if (!TextUtils.isEmpty(phoneticGiven)) {
builder.appendName(phoneticGiven);
mSb.append(phoneticGiven);
}
final String phoneticName = mSb.toString().trim();
int phoneticNameStyle = builder.getInt(StructuredName.PHONETIC_NAME_STYLE);
if (phoneticNameStyle == PhoneticNameStyle.UNDEFINED) {
phoneticNameStyle = mSplitter.guessPhoneticNameStyle(phoneticName);
}
builder.appendName(phoneticName);
mNameLookupBuilder.appendNameShorthandLookup(builder, phoneticName,
phoneticNameStyle);
}
}
}