/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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 net.java.sip.communicator.plugin.addrbook.macosx;
import java.util.*;
import java.util.regex.*;
import net.java.sip.communicator.plugin.addrbook.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.contactsource.ContactDetail.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
/**
* Implements <tt>ContactQuery</tt> for the Address Book of Mac OS X.
*
* @author Lyubomir Marinov
*/
public class MacOSXAddrBookContactQuery
extends AbstractAddrBookContactQuery<MacOSXAddrBookContactSourceService>
{
/**
* The <tt>Logger</tt> used by the <tt>MacOSXAddrBookContactQuery</tt> class
* and its instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(MacOSXAddrBookContactQuery.class);
/**
* The properties of <tt>ABPerson</tt> which are to be queried by the
* <tt>MacOSXAddrBookContactQuery</tt> instances.
*/
public static final long[] ABPERSON_PROPERTIES
= new long[]
{
kABAIMInstantProperty(),
kABEmailProperty(),
kABFirstNameProperty(),
kABFirstNamePhoneticProperty(),
kABICQInstantProperty(),
kABJabberInstantProperty(),
kABLastNameProperty(),
kABLastNamePhoneticProperty(),
kABMiddleNameProperty(),
kABMiddleNamePhoneticProperty(),
kABMSNInstantProperty(),
kABNicknameProperty(),
kABPhoneProperty(),
kABYahooInstantProperty(),
kABPersonFlags(),
kABOrganizationProperty(),
kABMaidenNameProperty(),
kABBirthdayProperty(),
kABJobTitleProperty(),
kABHomePageProperty(),
kABURLsProperty(),
kABCalendarURIsProperty(),
kABAddressProperty(),
kABOtherDatesProperty(),
kABRelatedNamesProperty(),
kABDepartmentProperty(),
kABNoteProperty(),
kABTitleProperty(),
kABSuffixProperty()
};
/**
* The index of the <tt>kABAIMInstantProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABAIMInstantProperty = 0;
/**
* The index of the <tt>kABEmailProperty</tt> <tt>ABPerson</tt> property in
* {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABEmailProperty = 1;
/**
* The index of the <tt>kABFirstNameProperty</tt> <tt>ABPerson</tt> property
* in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABFirstNameProperty = 2;
/**
* The index of the <tt>kABFirstNamePhoneticProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABFirstNamePhoneticProperty = 3;
/**
* The index of the <tt>kABICQInstantProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABICQInstantProperty = 4;
/**
* The index of the <tt>kABJabberInstantProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABJabberInstantProperty = 5;
/**
* The index of the <tt>kABLastNameProperty</tt> <tt>ABPerson</tt> property
* in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABLastNameProperty = 6;
/**
* The index of the <tt>kABLastNamePhoneticProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABLastNamePhoneticProperty = 7;
/**
* The index of the <tt>kABMiddleNameProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABMiddleNameProperty = 8;
/**
* The index of the <tt>kABMiddleNamePhoneticProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABMiddleNamePhoneticProperty = 9;
/**
* The index of the <tt>kABMSNInstantProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABMSNInstantProperty = 10;
/**
* The index of the <tt>kABNicknameProperty</tt> <tt>ABPerson</tt> property
* in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABNicknameProperty = 11;
/**
* The index of the <tt>kABOrganizationProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABOrganizationProperty = 15;
/**
* The index of the <tt>kABPersonFlags</tt> <tt>ABPerson</tt> property in
* {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABPersonFlags = 14;
/**
* The index of the <tt>kABPhoneProperty</tt> <tt>ABPerson</tt> property in
* {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABPhoneProperty = 12;
/**
* The flag which indicates that an <tt>ABRecord</tt> is to be displayed as
* a company.
*/
public static final long kABShowAsCompany = 1;
/**
* The mask which extracts the <tt>kABShowAsXXX</tt> flag from the
* <tt>personFlags</tt> of an <tt>ABPerson</tt>.
*/
public static final long kABShowAsMask = 7;
/**
* The index of the <tt>kABYahooInstantProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABYahooInstantProperty = 13;
/**
* The index of the <tt>kABMaidenNameProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABMaidenNameProperty = 16;
/**
* The index of the <tt>kABBirthdayProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABBirthdayProperty = 17;
/**
* The index of the <tt>kABJobTitleProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABJobTitleProperty = 18;
/**
* The index of the <tt>kABHomePageProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABHomePageProperty = 19;
/**
* The index of the <tt>kABURLsProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABURLsProperty = 20;
/**
* The index of the <tt>kABCalendarURIsProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABCalendarURIsProperty = 21;
/**
* The index of the <tt>kABAddressProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABAddressProperty = 22;
/**
* The index of the <tt>kABOtherDatesProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABOtherDatesProperty = 23;
/**
* The index of the <tt>kABRelatedNamesProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABRelatedNamesProperty = 24;
/**
* The index of the <tt>kABDepartmentProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABDepartmentProperty = 25;
/**
* The index of the <tt>kABNoteProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABNoteProperty = 26;
/**
* The index of the <tt>kABTitleProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABTitleProperty = 27;
/**
* The index of the <tt>kABSuffixProperty</tt> <tt>ABPerson</tt>
* property in {@link #ABPERSON_PROPERTIES}.
*/
public static final int kABSuffixProperty = 28;
/**
* The regex which matches the superfluous parts of an <tt>ABMultiValue</tt>
* label.
*/
private static final Pattern LABEL_PATTERN
= Pattern.compile(
"kAB|Email|Phone|Label|(\\p{Punct}*)",
Pattern.CASE_INSENSITIVE);
static
{
System.loadLibrary("jmacosxaddrbook");
}
/**
* Initializes a new <tt>MacOSXAddrBookContactQuery</tt> which is to perform
* a specific <tt>query</tt> in the Address Book of Mac OS X on behalf of a
* specific <tt>MacOSXAddrBookContactSourceService</tt>.
*
* @param contactSource the <tt>MacOSXAddrBookContactSourceService</tt>
* which is to perform the new <tt>ContactQuery</tt> instance
* @param query the <tt>Pattern</tt> for which <tt>contactSource</tt> i.e.
* the Address Book of Mac OS X is being queried
*/
public MacOSXAddrBookContactQuery(
MacOSXAddrBookContactSourceService contactSource,
Pattern query)
{
super(contactSource, query);
}
/**
* Gets the <tt>imageData</tt> of a specific <tt>ABPerson</tt> instance.
*
* @param person the pointer to the <tt>ABPerson</tt> instance to get the
* <tt>imageData</tt> of
* @return the <tt>imageData</tt> of the specified <tt>ABPerson</tt>
* instance
*/
public static native byte[] ABPerson_imageData(long person);
/**
* Gets the values of a specific set of <tt>ABRecord</tt> properties for a
* specific <tt>ABRecord</tt> instance.
*
* @param record the pointer to the <tt>ABRecord</tt> to get the property
* values of
* @param properties the set of <tt>ABRecord</tt> properties to get the
* values of
* @return the values of the specified set of <tt>ABRecord</tt> properties
* for the specified <tt>ABRecord</tt> instance
*/
public static native Object[] ABRecord_valuesForProperties(
long record,
long[] properties);
/**
* Returns the unique id of a record.
* @param record the record which id is retrieved.
* @return the record id.
*/
public static native String ABRecord_uniqueId(long record);
/**
* Sets property for the supplied person id.
* @param id the person id
* @param property the property to use.
* @param subPropety any sub property if available.
* @param value the value to set.
* @return whether the result was successfully added.
*/
public static native boolean setProperty(
String id, long property, String subPropety, Object value);
/**
* Remove a property.
* @param id the person id.
* @param property the property.
* @return whether the result was successfully removed.
*/
public static native boolean removeProperty(String id, long property);
/**
* Removes a contact from the address book.
*
* @param id the person id.
*
* @return whether the contact was successfully removed.
*/
public static native boolean deleteContact(String id);
/**
* Creates a new address book contact.
*
* @return The identifier of the created contact. null if failed.
*/
public static native String createContact();
/**
* Gets the pointer of the given contact.
*
* @param id the person id.
*
* @return The pointer of the given contact. Null if failed.
*/
public static native long getContactPointer(String id);
/**
* Initializes a new <tt>ContactDetail</tt> instance which is to reperesent
* a specific contact address that is the value of a specific
* <tt>ABPerson</tt> property and, optionally, has a specific label.
*
* @param property the index in {@link #ABPERSON_PROPERTIES} of the
* <tt>ABPerson</tt> property to be represented by <tt>ContactDetail</tt>
* @param contactAddress the contact address to be represented by the new
* <tt>ContactDetail</tt> instance
* @param label an optional label to be added to the set of labels, if any,
* determined by <tt>property</tt>
* @param id The id of the detail.
*
* @return a new <tt>ContactDetail</tt> instance which represents the
* specified <tt>contactAddress</tt>
*/
private ContactDetail createContactDetail(
int property,
String contactAddress,
Object label,
String additionalProperty,
String id)
{
Category c;
SubCategory sc = null;
switch (property)
{
case kABEmailProperty:
c = Category.Email;
break;
case kABPhoneProperty:
c = Category.Phone;
break;
case kABAIMInstantProperty:
sc = SubCategory.AIM;
c = Category.InstantMessaging;
break;
case kABICQInstantProperty:
sc = SubCategory.ICQ;
c = Category.InstantMessaging;
break;
case kABJabberInstantProperty:
sc = SubCategory.Jabber;
c = Category.InstantMessaging;
break;
case kABMSNInstantProperty:
sc = SubCategory.Skype;
c = Category.InstantMessaging;
break;
case kABYahooInstantProperty:
sc = SubCategory.Yahoo;
c = Category.InstantMessaging;
break;
case kABMaidenNameProperty:
case kABFirstNameProperty:
sc = SubCategory.Name;
c = Category.Personal;
break;
case kABFirstNamePhoneticProperty:
sc = SubCategory.Name;
c = Category.Personal;
break;
case kABLastNameProperty:
sc = SubCategory.LastName;
c = Category.Personal;
break;
case kABLastNamePhoneticProperty:
sc = SubCategory.LastName;
c = Category.Personal;
break;
case kABMiddleNameProperty:
case kABMiddleNamePhoneticProperty:
case kABNicknameProperty:
sc = SubCategory.Nickname;
c = Category.Personal;
break;
case kABBirthdayProperty:
case kABURLsProperty:
case kABHomePageProperty:
sc = SubCategory.HomePage;
c = Category.Personal;
break;
case kABOtherDatesProperty:
case kABRelatedNamesProperty:
case kABNoteProperty:
case kABTitleProperty:
case kABSuffixProperty:
c = Category.Personal;
break;
case kABOrganizationProperty:
case kABJobTitleProperty:
sc = SubCategory.JobTitle;
c = Category.Organization;
break;
case kABDepartmentProperty:
c = Category.Organization;
sc = SubCategory.Name;
break;
case kABAddressProperty:
c = Category.Address;
break;
default:
c = null;
break;
}
if (sc == null)
{
if (label == null)
sc = null;
else
{
sc = getSubCategoryFromLabel(label);
}
}
SubCategory[] subCategories;
SubCategory additionalSubCategory = null;
if(additionalProperty != null)
additionalSubCategory = getSubCategoryFromLabel(additionalProperty);
if(additionalSubCategory != null)
subCategories = new SubCategory[]
{ sc, additionalSubCategory };
else
subCategories = new SubCategory[]{ sc };
return new MacOSXAddrBookContactDetail(
property,
contactAddress,
c,
subCategories,
additionalProperty,
id);
}
/**
* Returns the SubCategory corresponding to the given label.
*
* @param label the label to match to a <tt>SubDirectory</tt>
* @return the <tt>SubDirectory</tt> corresponding to the
* given label
*/
private SubCategory getSubCategoryFromLabel(Object label)
{
String labelString
= LABEL_PATTERN.matcher((String) label).replaceAll("").trim();
if (labelString.length() < 1)
return null;
SubCategory subCategory = null;
if (labelString.equalsIgnoreCase("home"))
subCategory = SubCategory.Home;
else if (labelString.equalsIgnoreCase("work"))
subCategory = SubCategory.Work;
else if (labelString.equalsIgnoreCase("other"))
subCategory = SubCategory.Other;
else if (labelString.equalsIgnoreCase("mobile"))
subCategory = SubCategory.Mobile;
else if (labelString.equalsIgnoreCase("homepage"))
subCategory = SubCategory.HomePage;
else if (labelString.equalsIgnoreCase("street"))
subCategory = SubCategory.Street;
else if (labelString.equalsIgnoreCase("state"))
subCategory = SubCategory.State;
else if (labelString.equalsIgnoreCase("ZIP"))
subCategory = SubCategory.PostalCode;
else if (labelString.equalsIgnoreCase("country"))
subCategory = SubCategory.Country;
else if (labelString.equalsIgnoreCase("city"))
subCategory = SubCategory.City;
else if (labelString.equalsIgnoreCase("InstantMessageUsername"))
subCategory = SubCategory.Nickname;
else if (labelString.equalsIgnoreCase("workfax"))
subCategory = SubCategory.Fax;
else if (labelString.equalsIgnoreCase("fax"))
subCategory = SubCategory.Fax;
return subCategory;
}
/**
* Calls back to a specific <tt>PtrCallback</tt> for each <tt>ABPerson</tt>
* found in the Address Book of Mac OS X which matches a specific
* <tt>String</tt> query.
*
* @param query the <tt>String</tt> for which the Address Book of Mac OS X
* is to be queried. <b>Warning</b>: Ignored at the time of this writing.
* @param callback the <tt>PtrCallback</tt> to be notified about the
* matching <tt>ABPerson</tt>s
*/
private static native void foreachPerson(
String query,
PtrCallback callback);
/**
* Gets the <tt>contactDetails</tt> to be set on a <tt>SourceContact</tt>
* which is to represent an <tt>ABPerson</tt> specified by the values of its
* {@link #ABPERSON_PROPERTIES}.
*
* @param values the values of the <tt>ABPERSON_PROPERTIES</tt> which
* represent the <tt>ABPerson</tt> to get the <tt>contactDetails</tt> of
* @param id The id of the detail.
*
* @return the <tt>contactDetails</tt> to be set on a <tt>SourceContact</tt>
* which is to represent the <tt>ABPerson</tt> specified by <tt>values</tt>
*/
private List<ContactDetail> getContactDetails(Object[] values, String id)
{
List<ContactDetail> contactDetails = new LinkedList<ContactDetail>();
for (int i = 0; i < ABPERSON_PROPERTIES.length; i++)
{
int property = i;
Object value = values[property];
if (value instanceof String)
{
String stringValue = (String) value;
if (stringValue.length() != 0)
{
if (kABPhoneProperty == property)
stringValue
= AddrBookActivator.getPhoneNumberI18nService()
.normalize(stringValue);
contactDetails.add(
setCapabilities(
createContactDetail(
property,
stringValue,
null,
null,
id),
property));
}
}
else if (value instanceof Object[])
{
parseMultiDetails(contactDetails,
(Object[]) value,
property,
null,
id);
}
}
return contactDetails;
}
/**
* Parses the multi value data resulting it in contact details.
* @param contactDetails the result list
* @param multiValue the values to parse.
* @param property the current property being parsed.
* @param id The id of the detail.
*/
private void parseMultiDetails(
List<ContactDetail> contactDetails,
Object[] multiValue,
int property,
String label,
String id)
{
if(multiValue == null)
return;
for (int multiValueIndex = 0;
multiValueIndex < multiValue.length;
multiValueIndex += 2)
{
Object subValue = multiValue[multiValueIndex];
if (subValue instanceof String)
{
String stringSubValue = (String) subValue;
if (stringSubValue.length() != 0)
{
if (kABPhoneProperty == property)
{
stringSubValue
= AddrBookActivator.getPhoneNumberI18nService()
.normalize(stringSubValue);
}
Object l = multiValue[multiValueIndex + 1];
contactDetails.add(
setCapabilities(
createContactDetail(
property,
stringSubValue,
l,
label,
id),
property));
}
}
else if (subValue instanceof Object[])
{
String l = null;
Object lObject = multiValue[multiValueIndex + 1];
if(lObject instanceof String)
l = (String)lObject;
parseMultiDetails(contactDetails,
(Object[]) subValue,
property,
l,
id);
}
}
}
/**
* Gets the <tt>displayName</tt> to be set on a <tt>SourceContact</tt>
* which is to represent an <tt>ABPerson</tt> specified by the values of its
* {@link #ABPERSON_PROPERTIES}.
*
* @param values the values of the <tt>ABPERSON_PROPERTIES</tt> which
* represent the <tt>ABPerson</tt> to get the <tt>displayName</tt> of
* @return the <tt>displayName</tt> to be set on a <tt>SourceContact</tt>
* which is to represent the <tt>ABPerson</tt> specified by <tt>values</tt>
*/
private static String getDisplayName(Object[] values)
{
long personFlags
= (values[kABPersonFlags] instanceof Long)
? ((Long) values[kABPersonFlags]).longValue()
: 0;
String displayName;
if ((personFlags & kABShowAsMask) == kABShowAsCompany)
{
displayName
= (values[kABOrganizationProperty] instanceof String)
? (String) values[kABOrganizationProperty]
: "";
if (displayName.length() != 0)
return displayName;
}
displayName
= (values[kABNicknameProperty] instanceof String)
? (String) values[kABNicknameProperty]
: "";
if (displayName.length() != 0)
return displayName;
String firstName
= (values[kABFirstNameProperty] instanceof String)
? (String) values[kABFirstNameProperty]
: "";
if ((firstName.length() == 0)
&& (values[kABFirstNamePhoneticProperty] instanceof String))
{
firstName = (String) values[kABFirstNamePhoneticProperty];
}
String lastName
= (values[kABLastNameProperty] instanceof String)
? (String) values[kABLastNameProperty]
: "";
if ((lastName.length() == 0)
&& (values[kABLastNamePhoneticProperty] instanceof String))
lastName = (String) values[kABLastNamePhoneticProperty];
if ((lastName.length() == 0)
&& (values[kABMiddleNameProperty] instanceof String))
lastName = (String) values[kABMiddleNameProperty];
if ((lastName.length() == 0)
&& (values[kABMiddleNamePhoneticProperty] instanceof String))
lastName = (String) values[kABMiddleNamePhoneticProperty];
if (firstName.length() == 0)
displayName = lastName;
else
{
displayName
= (lastName.length() == 0)
? firstName
: (firstName + " " + lastName);
}
if (displayName.length() != 0)
return displayName;
for (int i = 0; i < ABPERSON_PROPERTIES.length; i++)
{
Object value = values[i];
if (value instanceof String)
{
String stringValue = (String) value;
if (stringValue.length() != 0)
{
displayName = stringValue;
break;
}
}
else if (value instanceof Object[])
{
Object[] multiValue = (Object[]) value;
for (int multiValueIndex = 0;
multiValueIndex < multiValue.length;
multiValueIndex += 2)
{
Object subValue = multiValue[multiValueIndex];
if (subValue instanceof String)
{
String stringSubValue = (String) subValue;
if (stringSubValue.length() != 0)
{
displayName = stringSubValue;
break;
}
}
}
}
}
return displayName;
}
/**
* Gets the organization name to be set on a <tt>SourceContact</tt>.
*
* @param values the values of the <tt>ABPERSON_PROPERTIES</tt> which
* represent the <tt>ABPerson</tt> to get the organization name of.
*
* @return The organization name to be set on a <tt>SourceContact</tt>.
*/
private static String getOrganization(Object[] values)
{
String organization = "";
long personFlags
= (values[kABPersonFlags] instanceof Long)
? ((Long) values[kABPersonFlags]).longValue()
: 0;
if ((personFlags & kABShowAsMask) != kABShowAsCompany)
{
organization = (values[kABOrganizationProperty] instanceof String)
? (String) values[kABOrganizationProperty]
: "";
}
return organization;
}
/**
* Gets the value of the <tt>kABAIMInstantProperty</tt> constant.
*
* @return the value of the <tt>kABAIMInstantProperty</tt> constant
*/
public static native long kABAIMInstantProperty();
/**
* Gets the value of the <tt>kABEmailProperty</tt> constant.
*
* @return the value of the <tt>kABEmailProperty</tt> constant
*/
public static native long kABEmailProperty();
/**
* Gets the value of the <tt>kABFirstNameProperty</tt> constant.
*
* @return the value of the <tt>kABFirstNameProperty</tt> constant
*/
public static native long kABFirstNameProperty();
/**
* Gets the value of the <tt>kABFirstNamePhoneticProperty</tt> constant.
*
* @return the value of the <tt>kABFirstNamePhoneticProperty</tt> constant
*/
public static native long kABFirstNamePhoneticProperty();
/**
* Gets the value of the <tt>kABICQInstantProperty</tt> constant.
*
* @return the value of the <tt>kABICQInstantProperty</tt> constant
*/
public static native long kABICQInstantProperty();
/**
* Gets the value of the <tt>kABJabberInstantProperty</tt> constant.
*
* @return the value of the <tt>kABJabberInstantProperty</tt> constant
*/
public static native long kABJabberInstantProperty();
/**
* Gets the value of the <tt>kABLastNameProperty</tt> constant.
*
* @return the value of the <tt>kABLastNameProperty</tt> constant
*/
public static native long kABLastNameProperty();
/**
* Gets the value of the <tt>kABLastNamePhoneticProperty</tt> constant.
*
* @return the value of the <tt>kABLastNamePhoneticProperty</tt> constant
*/
public static native long kABLastNamePhoneticProperty();
/**
* Gets the value of the <tt>kABMiddleNameProperty</tt> constant.
*
* @return the value of the <tt>kABMiddleNameProperty</tt> constant
*/
public static native long kABMiddleNameProperty();
/**
* Gets the value of the <tt>kABMiddleNamePhoneticProperty</tt> constant.
*
* @return the value of the <tt>kABMiddleNamePhoneticProperty</tt> constant
*/
public static native long kABMiddleNamePhoneticProperty();
/**
* Gets the value of the <tt>kABMSNInstantProperty</tt> constant.
*
* @return the value of the <tt>kABMSNInstantProperty</tt> constant
*/
public static native long kABMSNInstantProperty();
/**
* Gets the value of the <tt>kABNicknameProperty</tt> constant.
*
* @return the value of the <tt>kABNicknameProperty</tt> constant
*/
public static native long kABNicknameProperty();
/**
* Gets the value of the <tt>kABOrganizationProperty</tt> constant.
*
* @return the value of the <tt>kABOrganizationProperty</tt> constant
*/
public static native long kABOrganizationProperty();
/**
* Gets the value of the <tt>kABPersonFlags</tt> constant.
*
* @return the value of the <tt>kABPersonFlags</tt> constant
*/
public static native long kABPersonFlags();
/**
* Gets the value of the <tt>kABPhoneProperty</tt> constant.
*
* @return the value of the <tt>kABPhoneProperty</tt> constant
*/
public static native long kABPhoneProperty();
/**
* Gets the value of the <tt>kABYahooInstantProperty</tt> constant.
*
* @return the value of the <tt>kABYahooInstantProperty</tt> constant
*/
public static native long kABYahooInstantProperty();
/**
* Gets the value of the <tt>kABMaidenNameProperty</tt> constant.
*
* @return the value of the <tt>kABMaidenNameProperty</tt> constant
*/
public static native long kABMaidenNameProperty();
/**
* Gets the value of the <tt>kABBirthdayProperty</tt> constant.
*
* @return the value of the <tt>kABBirthdayProperty</tt> constant
*/
public static native long kABBirthdayProperty();
/**
* Gets the value of the <tt>kABJobTitleProperty</tt> constant.
*
* @return the value of the <tt>kABJobTitleProperty</tt> constant
*/
public static native long kABJobTitleProperty();
/**
* Gets the value of the <tt>kABHomePageProperty</tt> constant.
*
* @return the value of the <tt>kABHomePageProperty</tt> constant
*/
public static native long kABHomePageProperty();
/**
* Gets the value of the <tt>kABURLsProperty</tt> constant.
*
* @return the value of the <tt>kABURLsProperty</tt> constant
*/
public static native long kABURLsProperty();
/**
* Gets the value of the <tt>kABCalendarURIsProperty</tt> constant.
*
* @return the value of the <tt>kABCalendarURIsProperty</tt> constant
*/
public static native long kABCalendarURIsProperty();
/**
* Gets the value of the <tt>kABAddressProperty</tt> constant.
*
* @return the value of the <tt>kABAddressProperty</tt> constant
*/
public static native long kABAddressProperty();
/**
* Gets the value of the <tt>kABOtherDatesProperty</tt> constant.
*
* @return the value of the <tt>kABOtherDatesProperty</tt> constant
*/
public static native long kABOtherDatesProperty();
/**
* Gets the value of the <tt>kABRelatedNamesProperty</tt> constant.
*
* @return the value of the <tt>kABRelatedNamesProperty</tt> constant
*/
public static native long kABRelatedNamesProperty();
/**
* Gets the value of the <tt>kABDepartmentProperty</tt> constant.
*
* @return the value of the <tt>kABDepartmentProperty</tt> constant
*/
public static native long kABDepartmentProperty();
/**
* Gets the value of the <tt>kABInstantMessageProperty</tt> constant.
*
* @return the value of the <tt>kABInstantMessageProperty</tt> constant
*/
public static native long kABInstantMessageProperty();
/**
* Gets the value of the <tt>kABNoteProperty</tt> constant.
*
* @return the value of the <tt>kABNoteProperty</tt> constant
*/
public static native long kABNoteProperty();
/**
* Gets the value of the <tt>kABTitleProperty</tt> constant.
*
* @return the value of the <tt>kABTitleProperty</tt> constant
*/
public static native long kABTitleProperty();
/**
* Gets the value of the <tt>kABSuffixProperty</tt> constant.
*
* @return the value of the <tt>kABSuffixProperty</tt> constant
*/
public static native long kABSuffixProperty();
public static native String kABEmailWorkLabel();
public static native String kABEmailHomeLabel();
public static native String kABAddressHomeLabel();
public static native String kABAddressWorkLabel();
public static native String kABPhoneWorkLabel();
public static native String kABPhoneHomeLabel();
public static native String kABPhoneMobileLabel();
public static native String kABPhoneMainLabel();
public static native String kABPhoneWorkFAXLabel();
public static native String kABHomeLabel();
public static native String kABWorkLabel();
public static native String kABOtherLabel();
public static native String kABAddressStreetKey();
public static native String kABAddressCityKey();
public static native String kABAddressStateKey();
public static native String kABAddressZIPKey();
public static native String kABAddressCountryKey();
/**
* Determines whether a specific <tt>ABPerson</tt> property with a specific
* <tt>value</tt> matches the {@link #query} of this
* <tt>AsyncContactQuery</tt>.
*
* @param property the <tt>ABPerson</tt> property to check
* @param value the value of the <tt>property</tt> to check
* @return <tt>true</tt> if the specified <tt>value</tt> of the specified
* <tt>property</tt> matches the <tt>query</tt> of this
* <tt>AsyncContactQuery</tt>; otherwise, <tt>false</tt>
*/
private boolean matches(int property, String value)
{
return
query.matcher(value).find()
|| ((kABPhoneProperty == property) && phoneNumberMatches(value));
}
/**
* Determines whether an <tt>ABPerson</tt> represented by the values of its
* {@link #ABPERSON_PROPERTIES} matches {@link #query}.
*
* @param values the values of the <tt>ABPERSON_PROPERTIES</tt> which
* represent the <tt>ABPerson</tt> to be determined whether it matches
* <tt>query</tt>
* @return <tt>true</tt> if the <tt>ABPerson</tt> represented by the
* specified <tt>values</tt> matches <tt>query</tt>; otherwise,
* <tt>false</tt>
*/
private boolean matches(Object[] values)
{
int property = 0;
for (Object value : values)
{
if (value instanceof String)
{
if (matches(property, (String) value))
return true;
}
else if (value instanceof Object[])
{
Object[] multiValue = (Object[]) value;
for (int multiValueIndex = 0;
multiValueIndex < multiValue.length;
multiValueIndex += 2)
{
Object subValue = multiValue[multiValueIndex];
if ((subValue instanceof String)
&& matches(property, (String) subValue))
return true;
}
}
property++;
}
return false;
}
/**
* Notifies this <tt>MacOSXAddrBookContactQuery</tt> about a specific
* <tt>ABPerson</tt>.
*
* @param person a pointer to the <tt>ABPerson</tt> instance to notify about
* @return <tt>true</tt> if this <tt>MacOSXAddrBookContactQuery</tt> is to
* continue being called; otherwise, <tt>false</tt>
*/
private boolean onPerson(long person)
{
Object[] values
= ABRecord_valuesForProperties(person, ABPERSON_PROPERTIES);
final String id = ABRecord_uniqueId(person);
String displayName = getDisplayName(values);
if ((displayName.length() != 0)
&& (query.matcher(displayName).find() || matches(values)))
{
List<ContactDetail> contactDetails = getContactDetails(values, id);
if (!contactDetails.isEmpty())
{
final MacOSXAddrBookSourceContact sourceContact
= new MacOSXAddrBookSourceContact(
getContactSource(),
displayName,
contactDetails);
sourceContact.setData(SourceContact.DATA_ID, id);
sourceContact.setDisplayDetails(getOrganization(values));
try
{
byte[] image = ABPerson_imageData(person);
if (image != null)
sourceContact.setImage(image);
}
catch (OutOfMemoryError oome)
{
// Ignore it, the image is not vital.
}
addQueryResult(sourceContact);
}
}
return (getStatus() == QUERY_IN_PROGRESS);
}
/**
* Performs this <tt>AsyncContactQuery</tt> in a background <tt>Thread</tt>.
*
* @see AsyncContactQuery#run()
*/
@Override
protected void run()
{
foreachPerson(
query.toString(),
new PtrCallback()
{
@Override
public boolean callback(long person)
{
return onPerson(person);
}
});
}
/**
* Sets the capabilities of a specific <tt>ContactDetail</tt> (e.g.
* <tt>supportedOpSets</tt>) depending on the <tt>ABPerson</tt> property
* that it stands for.
*
* @param contactDetail the <tt>ContactDetail</tt> to set the capabilities
* of
* @param property the index in {@link #ABPERSON_PROPERTIES} of the
* <tt>ABPerson</tt> property represented by <tt>ContactDetail</tt>
* @return <tt>contactDetail</tt>
*/
private ContactDetail setCapabilities(
ContactDetail contactDetail,
int property)
{
List<Class<? extends OperationSet>> supportedOpSets
= new LinkedList<Class<? extends OperationSet>>();
Map<Class<? extends OperationSet>, String> preferredProtocols
= new HashMap<Class<? extends OperationSet>, String>();
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
switch (property)
{
case kABAIMInstantProperty:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.AIM);
break;
case kABEmailProperty:
supportedOpSets.add(OperationSetBasicTelephony.class);
break;
case kABICQInstantProperty:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.ICQ);
break;
case kABJabberInstantProperty:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.JABBER);
supportedOpSets.add(OperationSetBasicTelephony.class);
preferredProtocols.put(
OperationSetBasicTelephony.class,
ProtocolNames.JABBER);
break;
case kABPhoneProperty:
supportedOpSets.add(OperationSetBasicTelephony.class);
break;
default:
break;
}
contactDetail.setSupportedOpSets(supportedOpSets);
if (!preferredProtocols.isEmpty())
contactDetail.setPreferredProtocols(preferredProtocols);
return contactDetail;
}
/**
* Callback method when receiving notifications for inserted items.
*/
public void inserted(long person)
{
onPerson(person);
}
/**
* Callback method when receiving notifications for updated items.
*/
public void updated(long person)
{
SourceContact sourceContact =
findSourceContactByID(ABRecord_uniqueId(person));
if(sourceContact != null
&& sourceContact instanceof MacOSXAddrBookSourceContact)
{
// let's update the the details
Object[] values
= ABRecord_valuesForProperties(person, ABPERSON_PROPERTIES);
String displayName = getDisplayName(values);
final String id = ABRecord_uniqueId(person);
MacOSXAddrBookSourceContact editableSourceContact
= (MacOSXAddrBookSourceContact)sourceContact;
editableSourceContact.setDisplayName(displayName);
editableSourceContact.setDisplayDetails(getOrganization(values));
List<ContactDetail> contactDetails = getContactDetails(values, id);
editableSourceContact.setDetails(contactDetails);
fireContactChanged(sourceContact);
}
}
/**
* Callback method when receiving notifications for deleted items.
*/
public void deleted(String id)
{
SourceContact sourceContact = findSourceContactByID(id);
if(sourceContact != null)
fireContactRemoved(sourceContact);
}
/**
* Find the property from category and subcategories.
*
* @param category
* @param subCategories
* @return
*/
public static int getProperty(
Category category,
Collection<SubCategory> subCategories)
{
switch(category)
{
case Personal:
if(subCategories.contains(SubCategory.Name))
return kABFirstNameProperty;
else if(subCategories.contains(SubCategory.LastName))
return kABLastNameProperty;
else if(subCategories.contains(SubCategory.Nickname))
return kABNicknameProperty;
else if(subCategories.contains(SubCategory.HomePage))
return kABHomePageProperty;
break;
case Organization:
if(subCategories.contains(SubCategory.JobTitle))
return kABJobTitleProperty;
else
return kABDepartmentProperty;
case Email:
return kABEmailProperty;
case InstantMessaging:
if(subCategories.contains(SubCategory.AIM))
return kABAIMInstantProperty;
else if(subCategories.contains(SubCategory.ICQ))
return kABICQInstantProperty;
else if(subCategories.contains(SubCategory.Skype))
return kABMSNInstantProperty;
else if(subCategories.contains(SubCategory.Jabber))
return kABJabberInstantProperty;
else if(subCategories.contains(SubCategory.Yahoo))
return kABYahooInstantProperty;
break;
case Phone:
return kABPhoneProperty;
case Address:
return kABAddressProperty;
default: return -1;
}
return -1;
}
/**
* Finds the label from category and sub categories.
* @param subCategory
* @return
*/
public static String getLabel(
int property,
SubCategory subCategory,
String subProperty)
{
switch(property)
{
case kABEmailProperty:
if(subCategory == SubCategory.Home)
return kABEmailHomeLabel();
if(subCategory == SubCategory.Work)
return kABEmailWorkLabel();
break;
case kABICQInstantProperty:
case kABAIMInstantProperty:
case kABYahooInstantProperty:
case kABMSNInstantProperty:
case kABJabberInstantProperty:
return subProperty;
case kABPhoneProperty:
if(subCategory == SubCategory.Home)
return kABPhoneHomeLabel();
if(subCategory == SubCategory.Work)
return kABPhoneWorkLabel();
if(subCategory == SubCategory.Fax)
return kABPhoneWorkFAXLabel();
if(subCategory == SubCategory.Mobile)
return kABPhoneMobileLabel();
if(subCategory == SubCategory.Other)
return "other";
break;
case kABAddressProperty:
if(subCategory == SubCategory.Street)
return kABAddressStreetKey();
if(subCategory == SubCategory.City)
return kABAddressCityKey();
if(subCategory == SubCategory.State)
return kABAddressStateKey();
if(subCategory == SubCategory.Country)
return kABAddressCountryKey();
if(subCategory == SubCategory.PostalCode)
return kABAddressZIPKey();
break;
default: return null;
}
return null;
}
/**
* Adds a new empty contact, which will be filled in later.
*
* @param id The ID of the contact to add.
*/
public void addEmptyContact(String id)
{
if(id != null)
{
final MacOSXAddrBookSourceContact sourceContact
= new MacOSXAddrBookSourceContact(
getContactSource(),
null,
new LinkedList<ContactDetail>());
sourceContact.setData(SourceContact.DATA_ID, id);
addQueryResult(sourceContact);
}
}
/**
* Fires a contact changed event for the given contact.
*
* @param sourceContact The contact which has changed.
*/
public void contactChanged(SourceContact sourceContact)
{
fireContactChanged(sourceContact);
}
}