1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License
15 */
16package com.android.providers.contacts;
17
18import com.android.providers.contacts.SearchIndexManager.IndexBuilder;
19
20import android.content.ContentValues;
21import android.content.Context;
22import android.database.Cursor;
23import android.database.sqlite.SQLiteDatabase;
24import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
25import android.text.TextUtils;
26
27/**
28 * Handler for postal address data rows.
29 */
30public class DataRowHandlerForStructuredPostal extends DataRowHandler {
31
32    /**
33     * Specific list of structured fields.
34     */
35    private final String[] STRUCTURED_FIELDS = new String[] {
36            StructuredPostal.STREET,
37            StructuredPostal.POBOX,
38            StructuredPostal.NEIGHBORHOOD,
39            StructuredPostal.CITY,
40            StructuredPostal.REGION,
41            StructuredPostal.POSTCODE,
42            StructuredPostal.COUNTRY,
43    };
44
45    private final PostalSplitter mSplitter;
46
47    public DataRowHandlerForStructuredPostal(Context context, ContactsDatabaseHelper dbHelper,
48            ContactAggregator aggregator, PostalSplitter splitter) {
49        super(context, dbHelper, aggregator, StructuredPostal.CONTENT_ITEM_TYPE);
50        mSplitter = splitter;
51    }
52
53    @Override
54    public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
55            ContentValues values) {
56        fixStructuredPostalComponents(values, values);
57        return super.insert(db, txContext, rawContactId, values);
58    }
59
60    @Override
61    public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
62            Cursor c, boolean callerIsSyncAdapter) {
63        final long dataId = c.getLong(DataUpdateQuery._ID);
64        final ContentValues augmented = getAugmentedValues(db, dataId, values);
65        if (augmented == null) {    // No change
66            return false;
67        }
68
69        fixStructuredPostalComponents(augmented, values);
70        super.update(db, txContext, values, c, callerIsSyncAdapter);
71        return true;
72    }
73
74    /**
75     * Prepares the given {@link StructuredPostal} row, building
76     * {@link StructuredPostal#FORMATTED_ADDRESS} to match the structured
77     * values when missing. When structured components are missing, the
78     * unstructured value is assigned to {@link StructuredPostal#STREET}.
79     */
80    private void fixStructuredPostalComponents(ContentValues augmented, ContentValues update) {
81        final String unstruct = update.getAsString(StructuredPostal.FORMATTED_ADDRESS);
82
83        final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
84        final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
85
86        final PostalSplitter.Postal postal = new PostalSplitter.Postal();
87
88        if (touchedUnstruct && !touchedStruct) {
89            mSplitter.split(postal, unstruct);
90            postal.toValues(update);
91        } else if (!touchedUnstruct
92                && (touchedStruct || areAnySpecified(update, STRUCTURED_FIELDS))) {
93            postal.fromValues(augmented);
94            final String joined = mSplitter.join(postal);
95            update.put(StructuredPostal.FORMATTED_ADDRESS, joined);
96        }
97    }
98
99
100    @Override
101    public boolean hasSearchableData() {
102        return true;
103    }
104
105    @Override
106    public boolean containsSearchableColumns(ContentValues values) {
107        return values.containsKey(StructuredPostal.FORMATTED_ADDRESS);
108    }
109
110    @Override
111    public void appendSearchableData(IndexBuilder builder) {
112        builder.appendContentFromColumn(StructuredPostal.FORMATTED_ADDRESS);
113    }
114}
115