com.android.contacts.common.model.ContactBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.android.contacts.common.model.ContactBuilder.java

Source

/*
 * Copyright (C) 2014 Xiao-Long Chen <chillermillerlong@hotmail.com>
 *
 * 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.contacts.common.model;

import android.content.ContentValues;
import android.text.TextUtils;

import com.android.contacts.common.util.CallerMetaData;
import com.android.contacts.common.util.Constants;
import com.android.contacts.common.util.DataStatus;

import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.DisplayNameSources;
import android.util.Log;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

public class ContactBuilder {
    private static final String TAG = ContactBuilder.class.getSimpleName();

    private static final boolean DEBUG = false;

    /** Used to choose the proper directory ID */
    public static final int FORWARD_LOOKUP = 0;
    public static final int PEOPLE_LOOKUP = 1;
    public static final int REVERSE_LOOKUP = 2;

    // drawable for business will be generated by PhotoLoader
    public static final String PHOTO_URI_BUSINESS = null;

    private ArrayList<Address> mAddresses = new ArrayList<Address>();
    private ArrayList<PhoneNumber> mPhoneNumbers = new ArrayList<PhoneNumber>();
    private ArrayList<WebsiteUrl> mWebsites = new ArrayList<WebsiteUrl>();

    private int mDirectoryType;
    private long mDirectoryId = DirectoryId.DEFAULT;

    private Name mName;

    private String mNormalizedNumber;
    private String mFormattedNumber;
    private int mDisplayNameSource = DisplayNameSources.STRUCTURED_NAME;
    private Uri mPhotoUri;
    private String mPhotoUrl;

    private boolean mIsBusiness;

    private int mSpamCount;
    private String mInfoProviderName;
    private String mSuccinctLocation;

    public ContactBuilder(int directoryType, String normalizedNumber, String formattedNumber) {
        mDirectoryType = directoryType;
        mNormalizedNumber = normalizedNumber;
        mFormattedNumber = formattedNumber;
    }

    public ContactBuilder(Uri encodedContactUri) throws JSONException {
        String jsonData = encodedContactUri.getEncodedFragment();
        String directoryId = encodedContactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
        if (!TextUtils.isEmpty(directoryId)) {
            try {
                mDirectoryId = Long.parseLong(directoryId);
            } catch (NumberFormatException e) {
                Log.e(TAG, "Error parsing directory id of uri " + encodedContactUri, e);
            }
        }
        try {
            // name
            JSONObject json = new JSONObject(jsonData);
            JSONObject contact = json.optJSONObject(Contacts.CONTENT_ITEM_TYPE);
            JSONObject nameObj = contact.optJSONObject(StructuredName.CONTENT_ITEM_TYPE);
            mName = new Name(nameObj);

            if (contact != null) {
                // numbers
                if (contact.has(Phone.CONTENT_ITEM_TYPE)) {
                    String phoneData = contact.getString(Phone.CONTENT_ITEM_TYPE);
                    Object phoneObject = new JSONTokener(phoneData).nextValue();
                    JSONArray phoneNumbers;
                    if (phoneObject instanceof JSONObject) {
                        phoneNumbers = new JSONArray();
                        phoneNumbers.put(phoneObject);
                    } else {
                        phoneNumbers = contact.getJSONArray(Phone.CONTENT_ITEM_TYPE);
                    }
                    for (int i = 0; i < phoneNumbers.length(); ++i) {
                        JSONObject phoneObj = phoneNumbers.getJSONObject(i);
                        mPhoneNumbers.add(new PhoneNumber(phoneObj));
                    }
                }

                // address
                if (contact.has(StructuredPostal.CONTENT_ITEM_TYPE)) {
                    JSONArray addresses = contact.getJSONArray(StructuredPostal.CONTENT_ITEM_TYPE);
                    for (int i = 0; i < addresses.length(); ++i) {
                        JSONObject addrObj = addresses.getJSONObject(i);
                        mAddresses.add(new Address(addrObj));
                    }
                }

                // websites
                if (contact.has(Website.CONTENT_ITEM_TYPE)) {
                    JSONArray websites = contact.getJSONArray(Website.CONTENT_ITEM_TYPE);
                    for (int i = 0; i < websites.length(); ++i) {
                        JSONObject websiteObj = websites.getJSONObject(i);
                        final WebsiteUrl websiteUrl = new WebsiteUrl(websiteObj);
                        if (!TextUtils.isEmpty(websiteUrl.url)) {
                            mWebsites.add(new WebsiteUrl(websiteObj));
                        }
                    }
                }

                mSpamCount = contact.optInt(CallerMetaData.SPAM_COUNT, 0);
                mInfoProviderName = contact.optString(CallerMetaData.INFO_PROVIDER, null);
                mSuccinctLocation = contact.optString(CallerMetaData.SUCCINCT_LOCATION, null);
                mPhotoUrl = contact.optString(CallerMetaData.PHOTO_URL, null);
            }

        } catch (JSONException e) {
            Log.e(TAG, "Error parsing encoded fragment of uri " + encodedContactUri, e);
            throw e;
        }
    }

    public void setSpamCount(int spamCount) {
        mSpamCount = spamCount;
    }

    public int getSpamCount() {
        return mSpamCount;
    }

    public void setInfoProviderName(String infoProviderName) {
        mInfoProviderName = infoProviderName;
    }

    public String getInfoProviderName() {
        return mInfoProviderName;
    }

    public void setSuccinctLocation(String location) {
        mSuccinctLocation = location;
    }

    public String getSuccinctLocation() {
        return mSuccinctLocation;
    }

    public void addAddress(Address address) {
        if (DEBUG)
            Log.d(TAG, "Adding address");
        if (address != null) {
            mAddresses.add(address);
        }
    }

    public Address[] getAddresses() {
        return mAddresses.toArray(new Address[mAddresses.size()]);
    }

    public void addPhoneNumber(PhoneNumber phoneNumber) {
        if (DEBUG)
            Log.d(TAG, "Adding phone number");
        if (phoneNumber != null) {
            mPhoneNumbers.add(phoneNumber);
        }
    }

    public PhoneNumber[] getPhoneNumbers() {
        return mPhoneNumbers.toArray(new PhoneNumber[mPhoneNumbers.size()]);
    }

    public void addWebsite(WebsiteUrl website) {
        if (DEBUG)
            Log.d(TAG, "Adding website");
        if (website != null) {
            mWebsites.add(website);
        }
    }

    public WebsiteUrl[] getWebsites() {
        return mWebsites.toArray(new WebsiteUrl[mWebsites.size()]);
    }

    public void setName(Name name) {
        if (DEBUG)
            Log.d(TAG, "Setting name");
        if (name != null) {
            mName = name;
        }
    }

    public Name getName() {
        return mName;
    }

    public void setPhotoUri(String photoUri) {
        if (photoUri != null) {
            setPhotoUri(Uri.parse(photoUri));
        }
    }

    public void setPhotoUri(Uri photoUri) {
        if (DEBUG)
            Log.d(TAG, "Setting photo URI");
        mPhotoUri = photoUri;
    }

    public Uri getPhotoUri() {
        return mPhotoUri;
    }

    public void setPhotoUrl(String url) {
        if (!TextUtils.isEmpty(url)) {
            mPhotoUrl = url;
        }
    }

    public String getPhotoUrl() {
        return mPhotoUrl;
    }

    public long getDirectoryId() {
        return mDirectoryId;
    }

    public void setIsBusiness(boolean isBusiness) {
        if (DEBUG)
            Log.d(TAG, "Setting isBusiness to " + isBusiness);
        mIsBusiness = isBusiness;
    }

    public boolean isBusiness() {
        return mIsBusiness;
    }

    public Contact build() {
        if (mName == null) {
            throw new IllegalStateException("Name has not been set");
        }
        Uri lookupUri = null;

        if (mDirectoryType != FORWARD_LOOKUP && mDirectoryType != PEOPLE_LOOKUP
                && mDirectoryType != REVERSE_LOOKUP) {
            throw new IllegalStateException("Invalid directory type");
        }

        final ContentValues values = new ContentValues();
        values.put(ContactsContract.Data._ID, -1);
        final RawContact rawContact = new RawContact(values);

        final ContentValues numberValues = new ContentValues();
        numberValues.put(ContactsContract.Data._ID, -1);
        numberValues.put(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);

        // Use the incoming call's phone number if no other phone number
        // is specified. The reverse lookup source could present the phone
        // number differently (eg. without the area code).
        if (mPhoneNumbers.size() == 0) {
            PhoneNumber pn = new PhoneNumber();
            // Use the formatted number where possible
            pn.number = mFormattedNumber != null ? mFormattedNumber : mNormalizedNumber;
            pn.type = Phone.TYPE_MAIN;
            numberValues.put(ContactsContract.Data.DATA1, pn.number);
            addPhoneNumber(pn);
        }

        try {
            JSONObject contact = new JSONObject();

            // Insert the name
            contact.put(StructuredName.CONTENT_ITEM_TYPE, mName.getJsonObject());

            final String dataKeyPrefix = "data";

            // Insert phone numbers
            JSONArray phoneNumbers = new JSONArray();
            for (int i = 0; i < mPhoneNumbers.size(); i++) {
                phoneNumbers.put(mPhoneNumbers.get(i).getJsonObject());
                if (i + 1 < 15) { // data14 is max
                    numberValues.put(dataKeyPrefix + (i + 1), mPhoneNumbers.get(i).number);
                }
            }
            rawContact.addDataItemValues(numberValues);
            contact.put(Phone.CONTENT_ITEM_TYPE, phoneNumbers);

            final ContentValues addressValues = new ContentValues();
            addressValues.put(ContactsContract.Data._ID, -1);
            addressValues.put(ContactsContract.Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);

            // Insert addresses if there are any
            if (mAddresses.size() > 0) {
                JSONArray addresses = new JSONArray();
                for (int i = 0; i < mAddresses.size(); i++) {
                    addresses.put(mAddresses.get(i).getJsonObject());
                    if (i + 1 < 15) { // data14 is max
                        addressValues.put(dataKeyPrefix + (i + 1), mAddresses.get(i).formattedAddress);
                    }
                }
                contact.put(StructuredPostal.CONTENT_ITEM_TYPE, addresses);
                rawContact.addDataItemValues(addressValues);
            }

            // Insert websites if there are any
            if (mWebsites.size() > 0) {
                JSONArray websites = new JSONArray();
                for (int i = 0; i < mWebsites.size(); i++) {
                    websites.put(mWebsites.get(i).getJsonObject());
                }
                contact.put(Website.CONTENT_ITEM_TYPE, websites);
            }

            // add spam count and attribution
            contact.put(CallerMetaData.SPAM_COUNT, getSpamCount());
            contact.put(CallerMetaData.INFO_PROVIDER, getInfoProviderName());
            contact.put(CallerMetaData.SUCCINCT_LOCATION, getSuccinctLocation());
            contact.put(CallerMetaData.PHOTO_URL, getPhotoUrl());
            mPhotoUrl = getPhotoUrl();

            String json = new JSONObject().put(Contacts.DISPLAY_NAME, mName.displayName)
                    .put(Contacts.DISPLAY_NAME_SOURCE, mDisplayNameSource)
                    .put(Directory.EXPORT_SUPPORT, Directory.EXPORT_SUPPORT_ANY_ACCOUNT)
                    .put(Contacts.CONTENT_ITEM_TYPE, contact).toString();

            if (json != null) {
                long directoryId = -1;
                switch (mDirectoryType) {
                case FORWARD_LOOKUP:
                    directoryId = DirectoryId.NEARBY;
                    break;
                case PEOPLE_LOOKUP:
                    directoryId = DirectoryId.PEOPLE;
                    break;
                case REVERSE_LOOKUP:
                    // use null directory to be backwards compatible with old code
                    directoryId = DirectoryId.NULL;
                    break;
                }

                lookupUri = Contacts.CONTENT_LOOKUP_URI.buildUpon().appendPath(Constants.LOOKUP_URI_ENCODED)
                        .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
                        .encodedFragment(json).build();
            }

            final Contact contactToReturn = new Contact(lookupUri, lookupUri, lookupUri, mDirectoryId,
                    null /* lookupKey */, -1 /* id */, -1 /* nameRawContactId */, mDisplayNameSource,
                    0 /* photoId */, mPhotoUrl, mName.displayName, mName.givenName,
                    mName.phoneticGivenName /* phoneticName */, false /* starred */, null /* presence */,
                    false /* sendToVoicemail */, null /* customRingtone */, false /* isUserProfile */);

            contactToReturn.setStatuses(new ImmutableMap.Builder<Long, DataStatus>().build());
            final String accountName = contact.optString(ContactsContract.RawContacts.ACCOUNT_NAME, null);
            final String directoryName = lookupUri.getQueryParameter(Directory.DISPLAY_NAME);
            if (accountName != null) {
                final String accountType = contact.getString(ContactsContract.RawContacts.ACCOUNT_TYPE);
                contactToReturn.setDirectoryMetaData(directoryName, null, accountName, accountType,
                        contact.optInt(Directory.EXPORT_SUPPORT, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY));
            } else {
                contactToReturn.setDirectoryMetaData(directoryName, null, null, null,
                        contact.optInt(Directory.EXPORT_SUPPORT, Directory.EXPORT_SUPPORT_ANY_ACCOUNT));
            }

            final ContentValues nameValues = new ContentValues();
            nameValues.put(ContactsContract.Data._ID, -1);
            nameValues.put(ContactsContract.Data.DATA1, mName.displayName);
            nameValues.put(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
            rawContact.addDataItemValues(nameValues);

            contactToReturn.setRawContacts(new ImmutableList.Builder<RawContact>().add(rawContact).build());

            contactToReturn.setSpamCount(getSpamCount());
            contactToReturn.setProviderName(getInfoProviderName());

            return contactToReturn;
        } catch (JSONException e) {
            Log.e(TAG, "Failed to build contactToReturn", e);
            return null;
        }
    }

    // android.provider.ContactsContract.CommonDataKinds.StructuredPostal
    public static class Address {
        public String formattedAddress;
        public int type;
        public String label;
        public String street;
        public String poBox;
        public String neighborhood;
        public String city;
        public String region;
        public String postCode;
        public String country;

        public static Address createFormattedHome(String address) {
            Address a = new Address();
            a.formattedAddress = address;
            a.type = StructuredPostal.TYPE_HOME;
            return a;
        }

        public JSONObject getJsonObject() throws JSONException {
            JSONObject json = new JSONObject();
            json.putOpt(StructuredPostal.FORMATTED_ADDRESS, formattedAddress);
            json.put(StructuredPostal.TYPE, type);
            json.putOpt(StructuredPostal.LABEL, label);
            json.putOpt(StructuredPostal.STREET, street);
            json.putOpt(StructuredPostal.POBOX, poBox);
            json.putOpt(StructuredPostal.NEIGHBORHOOD, neighborhood);
            json.putOpt(StructuredPostal.CITY, city);
            json.putOpt(StructuredPostal.REGION, region);
            json.putOpt(StructuredPostal.POSTCODE, postCode);
            json.putOpt(StructuredPostal.COUNTRY, country);
            return json;
        }

        public Address() {
        }

        public Address(JSONObject json) throws JSONException {
            if (json.has(StructuredPostal.FORMATTED_ADDRESS)) {
                formattedAddress = json.getString(StructuredPostal.FORMATTED_ADDRESS);
            }
        }

        public String toString() {
            return "formattedAddress: " + formattedAddress + "; " + "type: " + type + "; " + "label: " + label
                    + "; " + "street: " + street + "; " + "poBox: " + poBox + "; " + "neighborhood: " + neighborhood
                    + "; " + "city: " + city + "; " + "region: " + region + "; " + "postCode: " + postCode + "; "
                    + "country: " + country;
        }
    }

    // android.provider.ContactsContract.CommonDataKinds.StructuredName
    public static class Name {
        public String displayName;
        public String givenName;
        public String familyName;
        public String prefix;
        public String middleName;
        public String suffix;
        public String phoneticGivenName;
        public String phoneticMiddleName;
        public String phoneticFamilyName;

        public static Name createDisplayName(String displayName) {
            Name name = new Name();
            name.displayName = displayName;
            return name;
        }

        public JSONObject getJsonObject() throws JSONException {
            JSONObject json = new JSONObject();
            json.putOpt(StructuredName.DISPLAY_NAME, displayName);
            json.putOpt(StructuredName.GIVEN_NAME, givenName);
            json.putOpt(StructuredName.FAMILY_NAME, familyName);
            json.putOpt(StructuredName.PREFIX, prefix);
            json.putOpt(StructuredName.MIDDLE_NAME, middleName);
            json.putOpt(StructuredName.SUFFIX, suffix);
            json.putOpt(StructuredName.PHONETIC_GIVEN_NAME, phoneticGivenName);
            json.putOpt(StructuredName.PHONETIC_MIDDLE_NAME, phoneticMiddleName);
            json.putOpt(StructuredName.PHONETIC_FAMILY_NAME, phoneticFamilyName);
            return json;
        }

        public Name(JSONObject json) throws JSONException {
            if (json != null) {
                displayName = json.optString(StructuredName.DISPLAY_NAME, null);
            }
        }

        public Name() {
        }

        public String toString() {
            return "displayName: " + displayName + "; " + "givenName: " + givenName + "; " + "familyName: "
                    + familyName + "; " + "prefix: " + prefix + "; " + "middleName: " + middleName + "; "
                    + "suffix: " + suffix + "; " + "phoneticGivenName: " + phoneticGivenName + "; "
                    + "phoneticMiddleName: " + phoneticMiddleName + "; " + "phoneticFamilyName: "
                    + phoneticFamilyName;
        }
    }

    // android.provider.ContactsContract.CommonDataKinds.Phone
    public static class PhoneNumber {
        public String number;
        public int type;
        public String label;

        public static PhoneNumber createMainNumber(String number) {
            PhoneNumber n = new PhoneNumber();
            n.number = number;
            n.type = Phone.TYPE_MAIN;
            return n;
        }

        public JSONObject getJsonObject() throws JSONException {
            JSONObject json = new JSONObject();
            json.put(Phone.NUMBER, number);
            json.put(Phone.TYPE, type);
            json.putOpt(Phone.LABEL, label);
            return json;
        }

        public PhoneNumber(JSONObject json) throws JSONException {
            number = json.getString(Phone.NUMBER);
            type = json.getInt(Phone.TYPE);
            if (json.has(Phone.LABEL)) {
                label = json.getString(Phone.LABEL);
            }
        }

        public PhoneNumber() {
        }

        public String toString() {
            return "number: " + number + "; " + "type: " + type + "; " + "label: " + label;
        }
    }

    // android.provider.ContactsContract.CommonDataKinds.Website
    public static class WebsiteUrl {
        public String url;
        public int type;
        public String label;

        public static WebsiteUrl createProfile(String url) {
            WebsiteUrl u = new WebsiteUrl();
            u.url = url;
            u.type = Website.TYPE_PROFILE;
            return u;
        }

        public JSONObject getJsonObject() throws JSONException {
            JSONObject json = new JSONObject();
            json.put(Website.URL, url);
            json.put(Website.TYPE, type);
            json.putOpt(Website.LABEL, label);
            return json;
        }

        public WebsiteUrl() {
        }

        public WebsiteUrl(JSONObject json) throws JSONException {
            if (json.has(Website.URL)) {
                url = json.getString(Website.URL);
            }
            if (json.has(Website.TYPE)) {
                type = json.getInt(Website.TYPE);
            }
            if (json.has(Website.LABEL)) {
                label = json.getString(Website.LABEL);
            }
        }

        public String toString() {
            return "url: " + url + "; " + "type: " + type + "; " + "label: " + label;
        }
    }
}