Java tutorial
/* * 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; } } }