Extends contact source apis to support editable contact sources. Fixes internationalization issues with contact source details. Adds additional categories and sub-categories of contact details.

cusax-fix
Yana Stamcheva 13 years ago
parent 02acd44641
commit 8b6b45aa53

@ -51,6 +51,7 @@ service.gui.ADD_GROUP_ERROR=Failed to add group with name: {0}.
service.gui.ADD_GROUP_EMPTY_NAME=The group name must not be empty.
service.gui.ADD_GROUP=Create group
service.gui.ADD_SUBCONTACT=&Add subcontact
service.gui.ADDRESS=Address
service.gui.ADMINISTRATOR=administrator
service.gui.ADVANCED=&Advanced
service.gui.ALL=&All
@ -122,6 +123,8 @@ service.gui.CHAT_ROOMS=Chat rooms
service.gui.CHAT_ROOM_SUBJECT_CHANGED={0} has changed the subject to {1}
service.gui.CHOOSE_CONTACT=Choose contact
service.gui.CHOOSE_ACCOUNT=Please select one of the listed accounts.
service.gui.CITY=City
service.gui.COUNTRY=Country
service.gui.SHOW_MORE_TOOLTIP=Click to show more results
service.gui.CLEAR=Clear
service.gui.CLOSE=Cl&ose
@ -175,6 +178,8 @@ service.gui.DRAG_FOR_SHARING=Drag here anything you want to share...
service.gui.DURATION=duration
service.gui.EDIT=&Edit
service.gui.EDITED_AT=edited at {0}
service.gui.EMAIL=Email
service.gui.EMAILS=Emails
service.gui.EMPTY_HISTORY=&Empty history
service.gui.ENABLE_DESKTOP_REMOTE_CONTROL=Enable desktop remote control
service.gui.ENABLE_TYPING_NOTIFICATIONS=Tell others when we are writing to them (send chat activity)
@ -191,6 +196,7 @@ service.gui.GENERAL_ERROR=General error
service.gui.GROUP_NAME=Group name
service.gui.FAILED_STATUS=Call failed
service.gui.FAILED_TO_JOIN_CHAT_ROOM=Failed to join chat room with name: {0}.
service.gui.FAX=Fax
service.gui.FFC_STATUS=Free for chat
service.gui.FILE=&File
service.gui.FILE_WAITING_TO_ACCEPT=Waiting for {0} to accept your file.
@ -241,6 +247,8 @@ service.gui.HIDE_MAIN_WINDOW=<DIV>Clicking the X window button will not exit the
but only <BR> hide it. If you wish to exit the application choose File/Quit.</DIV>
service.gui.HISTORY=&History
service.gui.HISTORY_CONTACT=History - {0}
service.gui.HOME=Home
service.gui.HOME_PAGE=Home page
service.gui.HOUR=Hour
service.gui.ICE=ICE
service.gui.IDENTIFIER=Identifier
@ -248,6 +256,7 @@ service.gui.IGNORE=&Ignore
service.gui.INSERT_SMILEY=Insert smiley
service.gui.INCOMING_CALL=Incoming call received from: {0}
service.gui.INCOMING_CALL_STATUS=Incoming call
service.gui.INSTANT_MESSAGINGS=IMs
service.gui.INITIATING_CALL_STATUS=Initiating call
service.gui.INVITATION=Invitation text
service.gui.INVITATION_RECEIVED=Invitation received
@ -269,6 +278,7 @@ service.gui.JITSI_WARNING_TITLE=SIP Communicator becomes Jitsi
service.gui.JOIN=&Join
service.gui.JOIN_AS=J&oin as
service.gui.CLOSE_CHAT_ROOM_DIALOG=C&lose
service.gui.JOB_TITLE=Job title
service.gui.JOIN_CHAT_ROOM=&Join chat room...
service.gui.JOIN_CHAT_ROOM_TITLE=Join chat room
service.gui.JOIN_CHAT_ROOM_NAME=Please enter the name of the chat room you would like to join.
@ -279,6 +289,7 @@ service.gui.KICK_FAILED_GENERAL_ERROR=Failed to kick {0}. A general server error
service.gui.KICK_FAILED_NOT_ALLOWED=Failed to kick {0}. The owner and the administrator of the room could not be kicked.
service.gui.KICK_FAILED_NOT_ENOUGH_PERMISSIONS=Failed to kick {0}. You don''t have enough privileges to do that.
service.gui.LAST=Last
service.gui.LAST_NAME=Last name
service.gui.LEAVE=&Leave
service.gui.LIMIT_REACHED_FOR_IP=You have too many existing registrations from the local IP address and the {0} server doesn''t allow to open any more of them.
service.gui.LOADING_ROOMS=Loading rooms...
@ -321,6 +332,7 @@ service.gui.MY_CHAT_ROOMS=Go to chat room...
service.gui.MY_CHAT_ROOMS_TITLE=Go to chat room
service.gui.MUTE=Mute
service.gui.MUTUALLY_ON_HOLD_STATUS=Mutually On Hold
service.gui.NAME=Name
service.gui.NETWORK=Network
service.gui.NETWORK_FAILURE=Network failure
service.gui.NEXT=&Next
@ -329,6 +341,7 @@ service.gui.NEW_MESSAGE=New message
service.gui.NEW_NAME=New name
service.gui.NEW_STATUS_MESSAGE=New status message
service.gui.NEW_STATUS_MESSAGE_SAVE=Save as custom message
service.gui.NICKNAME=Nickname
service.gui.NO=No
service.gui.NONE=None
service.gui.NO_CAMERA_AVAILABLE=No camera available
@ -357,12 +370,16 @@ service.gui.OPEN_IN_BROWSER=Open in &browser
service.gui.OPTIONS=Options
service.gui.OR=or
service.gui.OR_ENTER_PHONE_NUMBER=Or enter phone number here...
service.gui.ORGANIZATION=Organization
service.gui.OTHER=Other
service.gui.OWNER=owner of the room
service.gui.PASSWORD=Password
service.gui.PASSWORD_CHANGE_FAILURE=Password change failed
service.gui.PASSWORD_CHANGE_SUCCESS=Password successfully changed
service.gui.PASTE=&Paste
service.gui.PERSONAL=Personal
service.gui.PORT=Port
service.gui.POSTAL_CODE=Postal code
service.gui.PREFIX=Prefix
service.gui.PRESENCE=Presence
service.gui.PRESS_ENTER_FOR_SUGGESTIONS='Enter' for suggestions
@ -460,6 +477,7 @@ service.gui.STATUS_CHANGE_GENERAL_ERROR=Failed to change status for account: Use
service.gui.STATUS_CHANGE_NETWORK_FAILURE=Failed to change status for account: User name: {0}, Server name: {1}, due to a network problem.
service.gui.STATUS_MESSAGE_INFO=In the field below you can specify the new message you would like to use.
service.gui.STOP_SHARING=Stop sharing
service.gui.STREET=Street
service.gui.SUBJECT=Subject
service.gui.SUMMARY=Summary
service.gui.TELEPHONY=Telephony
@ -531,7 +549,8 @@ service.gui.NON_SECURE_CONNECTION=No secure connection can be made for account {
service.gui.UPDATE=Update
service.gui.MOBILE_PHONE=Mobile
service.gui.WORK_PHONE=Work
service.gui.PHONE=Home
service.gui.PHONE=Phone
service.gui.PHONES=Phones
service.gui.EDIT_NOT_SUPPORTED=Editing this account is not supported
service.gui.ZID_NAME_SET=ZRTP identifier's name:
@ -1657,5 +1676,5 @@ plugin.certconfig.REVOCATION_TITLE=Certificate revocation options
plugin.certconfig.REVOCATION_CHECK_ENABLED=CRL (Certificate Revocation List) check enabled
plugin.certconfig.REVOCATION_OCSP_ENABLED=OCSP (Online Certificate Status Protocol) check enabled
#Phone number contact source plugin
plugin.phonenumbercontactsource.DISPLAY_NAME=Phone numbers
# Phone number contact source plugin
plugin.phonenumbercontactsource.DISPLAY_NAME=Phone numbers

@ -304,7 +304,8 @@ public List<ContactDetail> getContactDetails(
* @return a list of all <tt>ContactDetail</tt>s corresponding to the given
* category
*/
public List<ContactDetail> getContactDetails(String category)
public List<ContactDetail> getContactDetails(
ContactDetail.Category category)
throws OperationNotSupportedException
{
// We don't support category for call history details, so we return null.

@ -160,8 +160,10 @@ private List<ContactDetail> getContactDetails(GoogleContactsEntry entry)
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
detail = new ContactDetail(mail, ContactDetail.CATEGORY_EMAIL,
new String[]{ContactDetail.LABEL_HOME});
detail = new ContactDetail(mail,
ContactDetail.Category.Email,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Home});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
@ -172,8 +174,10 @@ private List<ContactDetail> getContactDetails(GoogleContactsEntry entry)
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
detail = new ContactDetail(mail, ContactDetail.CATEGORY_EMAIL,
new String[]{ContactDetail.LABEL_WORK});
detail = new ContactDetail(mail,
ContactDetail.Category.Email,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Work});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
@ -188,8 +192,9 @@ private List<ContactDetail> getContactDetails(GoogleContactsEntry entry)
supportedOpSets.add(OperationSetPersistentPresence.class);
homePhone = PhoneNumberI18nService.normalize(homePhone);
detail = new ContactDetail(homePhone,
ContactDetail.CATEGORY_PHONE,
new String[]{ContactDetail.LABEL_HOME});
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Home});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
@ -204,8 +209,9 @@ private List<ContactDetail> getContactDetails(GoogleContactsEntry entry)
supportedOpSets.add(OperationSetPersistentPresence.class);
workPhone = PhoneNumberI18nService.normalize(workPhone);
detail = new ContactDetail(workPhone,
ContactDetail.CATEGORY_PHONE,
new String[]{ContactDetail.LABEL_WORK});
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Work});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
@ -220,8 +226,9 @@ private List<ContactDetail> getContactDetails(GoogleContactsEntry entry)
supportedOpSets.add(OperationSetPersistentPresence.class);
mobilePhone = PhoneNumberI18nService.normalize(mobilePhone);
detail = new ContactDetail(mobilePhone,
ContactDetail.CATEGORY_PHONE,
new String[]{ContactDetail.LABEL_MOBILE});
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Mobile});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
@ -231,9 +238,33 @@ private List<ContactDetail> getContactDetails(GoogleContactsEntry entry)
{
if(im.getValue() != GoogleContactsEntry.IMProtocol.OTHER)
{
detail = new ContactDetail(im.getKey(),
ContactDetail.CATEGORY_INSTANT_MESSAGING,
new String[]{im.getValue().toString()});
ContactDetail.SubCategory imSubCat = null;
switch(im.getValue())
{
case AIM:
imSubCat = ContactDetail.SubCategory.AIM;
break;
case ICQ:
imSubCat = ContactDetail.SubCategory.ICQ;
break;
case YAHOO:
imSubCat = ContactDetail.SubCategory.Yahoo;
break;
case JABBER:
imSubCat = ContactDetail.SubCategory.Jabber;
break;
case MSN:
imSubCat = ContactDetail.SubCategory.MSN;
break;
case GOOGLETALK:
imSubCat = ContactDetail.SubCategory.GoogleTalk;
break;
}
detail = new ContactDetail(
im.getKey(),
ContactDetail.Category.InstantMessaging,
new ContactDetail.SubCategory[]{imSubCat});
setIMCapabilities(detail, im.getValue());

@ -1654,7 +1654,7 @@ else if(d instanceof MobilePhoneDetail)
localizedType =
GuiActivator.getResources().
getI18NString(
"service.gui.PHONE");
"service.gui.HOME");
}
phones.add(pnd.getNumber());

@ -284,7 +284,7 @@ else if (opSetClass.equals(
String category = telephonyContact.getCategory();
if (category != null && category.equals(ContactDetail.CATEGORY_PHONE))
if (category != null && category.equals(ContactDetail.Category.Phone))
{
int index = findPhoneItemIndex();
if (index < 0)
@ -299,7 +299,7 @@ else if (opSetClass.equals(
category = ((ContactMenuItem) lastComp).getCategory();
if (category != null
&& category.equals(ContactDetail.CATEGORY_PHONE))
&& category.equals(ContactDetail.Category.Phone))
addSeparator();
add(contactItem);
@ -322,7 +322,7 @@ private int findPhoneItemIndex()
{
String category = ((ContactMenuItem) c).getCategory();
if (category == null
|| !category.equals(ContactDetail.CATEGORY_PHONE))
|| !category.equals(ContactDetail.Category.Phone))
continue;
}
else if (c instanceof JSeparator)

@ -50,6 +50,11 @@ public class SourceContactRightButtonMenu
*/
private SIPCommMenu callContactMenu;
/**
* Contact details menu.
*/
private SIPCommMenu contactDetailsMenu;
/**
* Add contact component.
*/
@ -111,7 +116,7 @@ private Component initCallMenu()
final ContactDetail detail = details.next();
// add all the contacts that support telephony to the call menu
JMenuItem callContactItem = new JMenuItem();
callContactItem.setText(detail.getContactAddress());
callContactItem.setText(detail.getDetail());
callContactItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
@ -139,14 +144,14 @@ public void actionPerformed(ActionEvent e)
else if (providersCount > 1)
{
new ChooseCallAccountDialog(
detail.getContactAddress(),
detail.getDetail(),
OperationSetBasicTelephony.class, providers)
.setVisible(true);
}
else // providersCount == 1
{
CallManager.createCall(
providers.get(0), detail.getContactAddress());
providers.get(0), detail.getDetail());
}
}
});

@ -1955,7 +1955,7 @@ else if (details.size() > 1)
final ContactDetail detail = detailsIter.next();
JMenuItem addMenuItem
= new JMenuItem(detail.getContactAddress());
= new JMenuItem(detail.getDetail());
((JMenu) addContactComponentTmp).add(addMenuItem);
addMenuItem.addActionListener(new ActionListener()
@ -1995,7 +1995,7 @@ public static void showAddContactDialog(ContactDetail contactDetail)
if (preferredProvider != null)
dialog.setSelectedAccount(preferredProvider);
dialog.setContactAddress(contactDetail.getContactAddress());
dialog.setContactAddress(contactDetail.getDetail());
dialog.setVisible(true);
}

@ -549,7 +549,7 @@ else if(d instanceof MobilePhoneDetail)
localizedType =
GuiActivator.getResources().
getI18NString(
"service.gui.PHONE");
"service.gui.HOME");
}
tip.addLine(null, (pnd.getNumber() +

@ -12,6 +12,8 @@
import javax.swing.*;
import org.jitsi.service.resources.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.contactlist.*;
import net.java.sip.communicator.impl.gui.utils.*;
@ -20,7 +22,6 @@
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.globalstatus.*;
import net.java.sip.communicator.util.*;
/**
* The <tt>SourceUIContact</tt> is the implementation of the UIContact for the
@ -70,8 +71,8 @@ public SourceUIContact( SourceContact contact,
if(contact.getContactDetails() != null)
for(ContactDetail detail : contact.getContactDetails())
{
if(detail.getContactAddress() != null)
searchStrings.add(detail.getContactAddress());
if(detail.getDetail() != null)
searchStrings.add(detail.getDetail());
}
searchStrings.add(contact.getDisplayName());
@ -211,7 +212,12 @@ public List<UIContactDetail> getContactDetails()
{
ContactDetail detail = details.next();
resultList.add(new SourceContactDetail(detail, null, sourceContact));
resultList.add(new SourceContactDetail(
detail,
getInternationalizedLabel(detail.getCategory()),
getInternationalizedLabels(
detail.getSubCategories().iterator()),
null, sourceContact));
}
return resultList;
}
@ -243,7 +249,12 @@ public List<UIContactDetail> getContactDetailsForOperationSet(
&& supportedOperationSets.contains(opSetClass))
{
resultList.add(new SourceContactDetail(
detail, opSetClass, sourceContact));
detail,
getInternationalizedLabel(detail.getCategory()),
getInternationalizedLabels(
detail.getSubCategories().iterator()),
opSetClass,
sourceContact));
}
}
return resultList;
@ -292,17 +303,22 @@ protected static class SourceContactDetail
* the underlying <tt>detail</tt> and the <tt>OperationSet</tt> class
* for it.
* @param detail the underlying <tt>ContactDetail</tt>
* @param category detail category string
* @param subCategories the detail list of sub-categories
* @param opSetClass the <tt>OperationSet</tt> class for the
* preferred protocol provider
* @param sourceContact the source contact
*/
public SourceContactDetail( ContactDetail detail,
String category,
Collection<String> subCategories,
Class<? extends OperationSet> opSetClass,
SourceContact sourceContact)
{
super( detail.getContactAddress(),
detail.getContactAddress(),
detail.getCategory(),
detail.getLabels(),
super( detail.getDetail(),
detail.getDetail(),
category,
subCategories,
null,
null,
null,
@ -391,27 +407,33 @@ public ExtendedTooltip getToolTip()
try
{
List<ContactDetail> details = sourceContact.getContactDetails(
ContactDetail.CATEGORY_PHONE);
ContactDetail.Category.Phone);
if (details != null && details.size() > 0)
addDetailsToToolTip(details,
ContactDetail.CATEGORY_PHONE + "s",
addDetailsToToolTip(
details,
GuiActivator.getResources()
.getI18NString("service.gui.PHONES"),
tip);
details = sourceContact.getContactDetails(
ContactDetail.CATEGORY_EMAIL);
ContactDetail.Category.Email);
if (details != null && details.size() > 0)
addDetailsToToolTip(details,
ContactDetail.CATEGORY_EMAIL + "s",
addDetailsToToolTip(
details,
GuiActivator.getResources()
.getI18NString("service.gui.EMAILS"),
tip);
details = sourceContact.getContactDetails(
ContactDetail.CATEGORY_INSTANT_MESSAGING);
ContactDetail.Category.InstantMessaging);
if (details != null && details.size() > 0)
addDetailsToToolTip(details,
ContactDetail.CATEGORY_INSTANT_MESSAGING + "s",
addDetailsToToolTip(
details,
GuiActivator.getResources()
.getI18NString("service.gui.INSTANT_MESSAGINGS"),
tip);
}
catch (OperationNotSupportedException e)
@ -445,16 +467,19 @@ private void addDetailsToToolTip( List<ContactDetail> details,
while (detailsIter.hasNext())
{
contactDetail = detailsIter.next();
Collection<String> labels = contactDetail.getLabels();
Collection<ContactDetail.SubCategory> subCategories
= contactDetail.getSubCategories();
JLabel[] jLabels = new JLabel[labels.size() + 1];
JLabel[] jLabels = new JLabel[subCategories.size() + 1];
int i = 0;
if (labels != null && labels.size() > 0)
if (subCategories != null && subCategories.size() > 0)
{
Iterator<String> labelsIter = labels.iterator();
Iterator<ContactDetail.SubCategory> labelsIter
= subCategories.iterator();
while(labelsIter.hasNext())
{
JLabel label = new JLabel(labelsIter.next().toLowerCase());
JLabel label = new JLabel(
getInternationalizedLabel(labelsIter.next()));
label.setFont(label.getFont().deriveFont(Font.BOLD));
label.setForeground(Color.GRAY);
@ -463,12 +488,152 @@ private void addDetailsToToolTip( List<ContactDetail> details,
}
}
jLabels[i] = new JLabel(contactDetail.getContactAddress());
jLabels[i] = new JLabel(contactDetail.getDetail());
toolTip.addLine(jLabels);
}
}
/**
* Returns the internationalized category corresponding to the given
* <tt>ContactDetail.Category</tt>.
*
* @param category the <tt>ContactDetail.SubCategory</tt>, for which we
* would like to obtain an internationalized label
* @return the internationalized label corresponding to the given category
*/
protected String getInternationalizedLabel(ContactDetail.Category category)
{
if (category == null)
return null;
String categoryString = null;
ResourceManagementService resources = GuiActivator.getResources();
switch(category)
{
case Address:
categoryString = resources.getI18NString("service.gui.ADDRESS");
break;
case Email:
categoryString = resources.getI18NString("service.gui.EMAIL");
break;
case Personal:
categoryString = resources.getI18NString("service.gui.PERSONAL");
break;
case Organization:
categoryString = resources.getI18NString("service.gui.ORGANIZATION");
break;
case Phone:
categoryString = resources.getI18NString("service.gui.PHONE");
break;
case InstantMessaging:
categoryString = resources.getI18NString("service.gui.IM");
break;
}
return categoryString;
}
/**
* Returns a collection of internationalized string corresponding to the
* given subCategories.
*
* @param subCategories an Iterator over a list of
* <tt>ContactDetail.SubCategory</tt>s
* @return a collection of internationalized string corresponding to the
* given subCategories
*/
protected Collection<String> getInternationalizedLabels(
Iterator<ContactDetail.SubCategory> subCategories)
{
Collection<String> labels = new LinkedList<String>();
while (subCategories.hasNext())
{
labels.add(getInternationalizedLabel(subCategories.next()));
}
return labels;
}
/**
* Returns the internationalized label corresponding to the given category.
*
* @param subCategory the <tt>ContactDetail.SubCategory</tt>, for which we
* would like to obtain an internationalized label
* @return the internationalized label corresponding to the given category
*/
protected String getInternationalizedLabel(
ContactDetail.SubCategory subCategory)
{
if (subCategory == null)
return null;
String label = null;
ResourceManagementService resources = GuiActivator.getResources();
switch(subCategory)
{
case City:
label = resources.getI18NString("service.gui.CITY");
break;
case Country:
label = resources.getI18NString("service.gui.COUNTRY");
break;
case Fax:
label = resources.getI18NString("service.gui.FAX");
break;
case Home:
label = resources.getI18NString("service.gui.HOME");
break;
case HomePage:
label = resources.getI18NString("service.gui.HOME_PAGE");
break;
case JobTitle:
label = resources.getI18NString("service.gui.JOB_TITLE");
break;
case LastName:
label = resources.getI18NString("service.gui.LAST_NAME");
break;
case Mobile:
label = resources.getI18NString("service.gui.MOBILE_PHONE");
break;
case Name:
label = resources.getI18NString("service.gui.NAME");
break;
case Nickname:
label = resources.getI18NString("service.gui.NICKNAME");
break;
case Other:
label = resources.getI18NString("service.gui.OTHER");
break;
case PostalCode:
label = resources.getI18NString("service.gui.POSTAL_CODE");
break;
case Street:
label = resources.getI18NString("service.gui.STREET");
break;
case Work:
label = resources.getI18NString("service.gui.WORK_PHONE");
break;
case AIM:
case ICQ:
case Jabber:
case MSN:
case Yahoo:
case Skype:
case GoogleTalk:
case Facebook:
label = subCategory.value();
break;
}
return label;
}
/**
* Returns all custom action buttons for this notification contact.
*

@ -145,7 +145,7 @@ private List<ContactDetail> getContactDetails(LdapPersonFound person)
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
detail = new ContactDetail(mail, ContactDetail.CATEGORY_EMAIL,
detail = new ContactDetail(mail, ContactDetail.Category.Email,
null);
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
@ -161,8 +161,9 @@ private List<ContactDetail> getContactDetails(LdapPersonFound person)
supportedOpSets.add(OperationSetPersistentPresence.class);
homePhone = PhoneNumberI18nService.normalize(homePhone);
detail = new ContactDetail(homePhone,
ContactDetail.CATEGORY_PHONE,
new String[]{ContactDetail.LABEL_HOME});
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Home});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
@ -177,8 +178,9 @@ private List<ContactDetail> getContactDetails(LdapPersonFound person)
supportedOpSets.add(OperationSetPersistentPresence.class);
workPhone = PhoneNumberI18nService.normalize(workPhone);
detail = new ContactDetail(workPhone,
ContactDetail.CATEGORY_PHONE,
new String[]{ContactDetail.LABEL_WORK});
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Work});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
@ -193,8 +195,9 @@ private List<ContactDetail> getContactDetails(LdapPersonFound person)
supportedOpSets.add(OperationSetPersistentPresence.class);
mobilePhone = PhoneNumberI18nService.normalize(mobilePhone);
detail = new ContactDetail(mobilePhone,
ContactDetail.CATEGORY_PHONE,
new String[]{ContactDetail.LABEL_MOBILE});
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Mobile});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}

@ -248,38 +248,95 @@ private ContactDetail createContactDetail(
String contactAddress,
Object label)
{
String c, l;
ContactDetail.Category c;
ContactDetail.SubCategory sc = null;
switch (property)
{
case kABEmailProperty:
c = ContactDetail.CATEGORY_EMAIL;
c = ContactDetail.Category.Email;
break;
case kABPhoneProperty:
c = ContactDetail.CATEGORY_PHONE;
c = ContactDetail.Category.Phone;
break;
case kABAIMInstantProperty:
sc = ContactDetail.SubCategory.AIM;
c = ContactDetail.Category.InstantMessaging;
break;
case kABICQInstantProperty:
sc = ContactDetail.SubCategory.ICQ;
c = ContactDetail.Category.InstantMessaging;
break;
case kABJabberInstantProperty:
sc = ContactDetail.SubCategory.Jabber;
c = ContactDetail.Category.InstantMessaging;
break;
case kABMSNInstantProperty:
sc = ContactDetail.SubCategory.MSN;
c = ContactDetail.Category.InstantMessaging;
break;
case kABYahooInstantProperty:
c = ContactDetail.CATEGORY_INSTANT_MESSAGING;
sc = ContactDetail.SubCategory.Yahoo;
c = ContactDetail.Category.InstantMessaging;
break;
default:
c = null;
break;
}
if (label == null)
l = null;
else
if (sc == null)
{
l = LABEL_PATTERN.matcher((String) label).replaceAll("").trim();
if (l.length() < 1)
l = null;
if (label == null)
sc = null;
else
{
sc = getSubCategoryFromLabel(label);
}
}
return new ContactDetail(contactAddress, c, new String[] { l });
return new ContactDetail(contactAddress,
c, new ContactDetail.SubCategory[] { sc });
}
/**
* Returns the ContactDetail.SubCategory corresponding to the given label.
*
* @param label the label to match to a <tt>ContactDetail.SubDirectory</tt>
* @return the <tt>ContactDetail.SubDirectory</tt> corresponding to the
* given label
*/
private ContactDetail.SubCategory getSubCategoryFromLabel(Object label)
{
String labelString
= LABEL_PATTERN.matcher((String) label).replaceAll("").trim();
if (labelString.length() < 1)
return null;
ContactDetail.SubCategory subCategory = null;
if (labelString.equalsIgnoreCase("home"))
subCategory = ContactDetail.SubCategory.Home;
else if (labelString.equalsIgnoreCase("work"))
subCategory = ContactDetail.SubCategory.Work;
else if (labelString.equalsIgnoreCase("other"))
subCategory = ContactDetail.SubCategory.Other;
else if (labelString.equalsIgnoreCase("mobile"))
subCategory = ContactDetail.SubCategory.Mobile;
else if (labelString.equalsIgnoreCase("homepage"))
subCategory = ContactDetail.SubCategory.HomePage;
else if (labelString.equalsIgnoreCase("street"))
subCategory = ContactDetail.SubCategory.Street;
else if (labelString.equalsIgnoreCase("ZIP"))
subCategory = ContactDetail.SubCategory.PostalCode;
else if (labelString.equalsIgnoreCase("country"))
subCategory = ContactDetail.SubCategory.Country;
else if (labelString.equalsIgnoreCase("city"))
subCategory = ContactDetail.SubCategory.City;
else if (labelString.equalsIgnoreCase("InstantMessageUsername"))
subCategory = ContactDetail.SubCategory.Nickname;
return subCategory;
}
/**

@ -215,6 +215,26 @@ private static native void foreachMailUser(
String query,
PtrCallback callback);
private ContactDetail.Category getCategory(int propIndex)
{
switch (propIndex)
{
case dispidEmail1EmailAddress:
case dispidEmail2EmailAddress:
case dispidEmail3EmailAddress:
case PR_EMAIL_ADDRESS:
return ContactDetail.Category.Email;
case PR_BUSINESS2_TELEPHONE_NUMBER:
case PR_BUSINESS_TELEPHONE_NUMBER:
case PR_HOME2_TELEPHONE_NUMBER:
case PR_HOME_TELEPHONE_NUMBER:
case PR_MOBILE_TELEPHONE_NUMBER:
return ContactDetail.Category.Phone;
default:
return null;
}
}
/**
* Gets the set of <tt>ContactDetail</tt> labels to be assigned to a
* property specified by its index in {@link #MAPI_MAILUSER_PROP_IDS}.
@ -224,37 +244,29 @@ private static native void foreachMailUser(
* @return the set of <tt>ContactDetail</tt> labels to be assigned to the
* property specified by its index in <tt>MAPI_MAILUSER_PROP_IDS</tt>
*/
private String[] getLabels(int propIndex)
private ContactDetail.SubCategory[] getSubCategories(int propIndex)
{
switch (propIndex)
{
case dispidEmail1EmailAddress:
case dispidEmail2EmailAddress:
case dispidEmail3EmailAddress:
case PR_EMAIL_ADDRESS:
return new String[] { ContactDetail.CATEGORY_EMAIL };
case PR_BUSINESS2_TELEPHONE_NUMBER:
case PR_BUSINESS_TELEPHONE_NUMBER:
return
new String[]
new ContactDetail.SubCategory[]
{
ContactDetail.CATEGORY_PHONE,
ContactDetail.LABEL_WORK
ContactDetail.SubCategory.Work
};
case PR_HOME2_TELEPHONE_NUMBER:
case PR_HOME_TELEPHONE_NUMBER:
return
new String[]
new ContactDetail.SubCategory[]
{
ContactDetail.CATEGORY_PHONE,
ContactDetail.LABEL_HOME
ContactDetail.SubCategory.Home
};
case PR_MOBILE_TELEPHONE_NUMBER:
return
new String[]
new ContactDetail.SubCategory[]
{
ContactDetail.CATEGORY_PHONE,
ContactDetail.LABEL_MOBILE
ContactDetail.SubCategory.Mobile
};
default:
return null;
@ -382,7 +394,8 @@ private boolean onMailUser(long iUnknown)
ContactDetail contactDetail
= new ContactDetail(
stringProp,
getLabels(propIndex));
getCategory(propIndex),
getSubCategories(propIndex));
contactDetail.setSupportedOpSets(supportedOpSets);
contactDetails.add(contactDetail);

@ -282,7 +282,7 @@ private SourceContact createSourceContact( SourceContact sourceContact,
sourceContact.getDisplayName(),
contactDetails);
genericContact.setDisplayDetails(contactDetail.getContactAddress());
genericContact.setDisplayDetails(contactDetail.getDetail());
return genericContact;
}

@ -169,7 +169,7 @@ else if(d instanceof MobilePhoneDetail)
{
localizedType =
PNContactSourceActivator.getResources()
.getI18NString("service.gui.PHONE");
.getI18NString("service.gui.HOME");
}
String contactName = contact.getDisplayName();

@ -36,138 +36,266 @@
public class ContactDetail
{
/**
* The standard/well-known category of a <tt>ContactDetail</tt> representing
* personal details, like name, last name, nickname.
* Defines all possible categories for a <tt>ContactDetail</tt>.
*/
public static final String CATEGORY_PERSONAL = "Personal";
/**
* The standard/well-known category of a <tt>ContactDetail</tt> representing
* organization details, like organization name and job title.
*/
public static final String CATEGORY_ORGANIZATION = "Organisation";
/**
* The standard/well-known category of a <tt>ContactDetail</tt> representing
* an e-mail address.
*/
public static final String CATEGORY_EMAIL = "Email";
/**
* The standard/well-known category of a <tt>ContactDetail</tt> representing
* a contact address for instant messaging.
*/
public static final String CATEGORY_INSTANT_MESSAGING = "Instant Messaging";
/**
* The standard/well-known category of a <tt>ContactDetail</tt> representing
* a phone number.
*/
public static final String CATEGORY_PHONE = "Phone";
/**
* The standard/well-known category of a <tt>ContactDetail</tt> representing
* a postal address.
*/
public static final String CATEGORY_ADDRESS = "Address";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* name. It could be an organization name or a personal name.
*/
public static final String LABEL_NAME = "Name";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* last name.
*/
public static final String LABEL_LAST_NAME = "Last name";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* nickname.
*/
public static final String LABEL_NICK_NAME = "Nickname";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing an
* address of a contact at their home.
*/
public static final String LABEL_HOME = "Home";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* mobile contact address (e.g. a cell phone number).
*/
public static final String LABEL_MOBILE = "Mobile";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing an
* address of a contact at their work.
*/
public static final String LABEL_WORK = "Work";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* fax number.
*/
public static final String LABEL_FAX = "Fax";
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* different number.
*/
public static final String LABEL_OTHER = "Other";
public enum Category
{
/**
* The standard/well-known category of a <tt>ContactDetail</tt>
* representing personal details, like name, last name, nickname.
*/
Personal("Personal"),
/**
* The standard/well-known category of a <tt>ContactDetail</tt>
* representing organization details, like organization name and job
* title.
*/
Organization("Organization"),
/**
* The standard/well-known category of a <tt>ContactDetail</tt>
* representing an e-mail address.
*/
Email("Email"),
/**
* The standard/well-known category of a <tt>ContactDetail</tt>
* representing a contact address for instant messaging.
*/
InstantMessaging("InstantMessaging"),
/**
* The standard/well-known category of a <tt>ContactDetail</tt>
* representing a phone number.
*/
Phone("Phone"),
/**
* The standard/well-known category of a <tt>ContactDetail</tt>
* representing a postal address.
*/
Address("Address");
/**
* Current enum value.
*/
private final String value;
/**
* Creates enum whith the specified value.
*
* @param value the value to set.
*/
Category(String value)
{
this.value = value;
}
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* country name.
*/
public static final String LABEL_COUNTRY = "Country";
/**
* Gets the value.
*
* @return the value
*/
public String value()
{
return value;
}
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* city name.
*/
public static final String LABEL_CITY = "City";
/**
* Creates enum from its value.
*
* @param value the enum's value.
* @return created enum.
*/
public static Category fromString(String value)
{
if (value != null)
{
for (Category category : Category.values())
{
if (value.equalsIgnoreCase(category.value()))
{
return category;
}
}
return null;
}
return null;
}
}
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* street address.
* Defines all possible sub-categories for a <tt>ContactDetail</tt>.
*/
public static final String LABEL_STREET = "Street";
public enum SubCategory
{
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a name. It could be an organization name or a personal
* name.
*/
Name("Name"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a last name.
*/
LastName("LastName"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a nickname.
*/
Nickname("Nickname"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a postal code.
*/
HomePage("HomePage"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing an address of a contact at their home.
*/
Home("Home"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a mobile contact address (e.g. a cell phone number).
*/
Mobile("Mobile"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing an address of a contact at their work.
*/
Work("Work"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a fax number.
*/
Fax("Fax"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a different number.
*/
Other("Other"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing an IM network (like for example jabber).
*/
AIM("AIM"),
ICQ("ICQ"),
MSN("MSN"),
Jabber("Jabber"),
Skype("Skype"),
Yahoo("Yahoo"),
Facebook("Facebook"),
GoogleTalk("GoogleTalk"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a country name.
*/
Country("Country"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a city name.
*/
City("City"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a street address.
*/
Street("Street"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a postal code.
*/
PostalCode("PostalCode"),
/**
* The standard/well-known label of a <tt>ContactDetail</tt>
* representing a job title.
*/
JobTitle("JobTitle");
/**
* Current enum value.
*/
private final String value;
/**
* Creates enum whith the specified value.
*
* @param value the value to set.
*/
SubCategory(String value)
{
this.value = value;
}
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* postal code.
*/
public static final String LABEL_POSTAL_CODE = "Postal code";
/**
* Gets the value.
*
* @return the value
*/
public String value()
{
return value;
}
/**
* The standard/well-known label of a <tt>ContactDetail</tt> representing a
* job title.
*/
public static final String LABEL_JOB_TITLE = "Job title";
/**
* Creates enum from its value.
*
* @param value the enum's value.
* @return created enum.
*/
public static SubCategory fromString(String value)
{
if (value != null)
{
for (SubCategory subCategory : SubCategory.values())
{
if (value.equalsIgnoreCase(subCategory.value()))
{
return subCategory;
}
}
return null;
}
return null;
}
}
/**
* The category of this <tt>ContactQuery</tt>. For example,
* {@link #CATEGORY_PHONE} or {@link #CATEGORY_EMAIL}.
*/
private final String category;
private final Category category;
/**
* The address of this contact detail. This should be the address through
* which the contact could be reached by one of the supported
* <tt>OperationSet</tt>s (e.g. by IM, call).
*/
private final String contactAddress;
protected String contactDetailValue;
/**
* The set of labels of this <tt>ContactDetail</tt>. The labels may be
* arbitrary and may include any of the standard/well-known labels defined
* by the <tt>LABEL_XXX</tt> constants of the <tt>ContactDetail</tt> class.
*/
private final Collection<String> labels = new LinkedList<String>();
private final Collection<SubCategory> subCategories
= new LinkedList<SubCategory>();
/**
* A mapping of <tt>OperationSet</tt> classes and preferred protocol
@ -190,11 +318,12 @@ public class ContactDetail
/**
* Creates a <tt>ContactDetail</tt> by specifying the contact address,
* corresponding to this detail.
* @param contactAddress the contact address corresponding to this detail
* @param contactDetailValue the contact detail value corresponding to this
* detail
*/
public ContactDetail(String contactAddress)
public ContactDetail(String contactDetailValue)
{
this(contactAddress, null);
this(contactDetailValue, null, null);
}
/**
@ -202,83 +331,33 @@ public ContactDetail(String contactAddress)
* specific contact address and which is to be optionally labeled with a
* specific set of labels.
*
* @param contactAddress the contact address to be represented by the new
* <tt>ContactDetail</tt> instance
* @param labels the set of labels with which the new <tt>ContactDetail</tt>
* instance is to be labeled. The labels may be arbitrary and may include
* any of the standard/well-known labels defined by the <tt>LABEL_XXX</tt>
* constants of the <tt>ContactDetail</tt> class. For the sake of
* convenience, <tt>null</tt> and duplicate values in the specified
* <tt>String[]</tt> <tt>labels</tt> will be ignored i.e. will not appear in
* the set of labels reported by the new <tt>ContactDetail</tt> instance
* later on. Additionally, the <tt>category</tt> of the new
* <tt>ContactDetail</tt> instance will be implied from the specified
* <tt>labels</tt> by looking for the standard/well-known categories defined
* by the <tt>CATEGORY_XXX</tt> constants of the <tt>ContactDetail</tt>
* class
*/
public ContactDetail(String contactAddress, String[] labels)
* @param contactDetailValue the contact detail value to be represented by
* the new <tt>ContactDetail</tt> instance
* @param category
* @param subCategories the set of sub categories with which the new
* <tt>ContactDetail</tt> instance is to be labeled.
*/
public ContactDetail( String contactDetailValue,
Category category,
SubCategory[] subCategories)
{
// contactAddress
this.contactAddress = contactAddress;
// the value of the detail
this.contactDetailValue = contactDetailValue;
// category & labels
String category = null;
this.category = category;
if (labels != null)
if (subCategories != null)
{
for (String label : labels)
for (SubCategory subCategory : subCategories)
{
if ((label != null) && !this.labels.contains(label))
if ((subCategory != null)
&& !this.subCategories.contains(subCategory))
{
if (label.equals(CATEGORY_EMAIL)
|| label.equals(CATEGORY_INSTANT_MESSAGING)
|| label.equals(CATEGORY_PHONE))
category = label;
else
this.labels.add(label);
this.subCategories.add(subCategory);
}
}
}
this.category = category;
}
/**
* Initializes a new <tt>ContactDetail</tt> instance which is to represent a
* specific contact address and which is to be optionally labeled with a
* specific category and a specific set of labels.
*
* @param contactAddress the contact address to be represented by the new
* <tt>ContactDetail</tt> instance
* @param category the category (such as one of the <tt>CATEGORY_XXX</tt>
* constants defined by the <tt>ContactDetail</tt> class, for example) to be
* assigned to the new <tt>ContactDetail</tt> instance
* @param labels the set of labels with which the new <tt>ContactDetail</tt>
* instance is to be labeled. The labels may be arbitrary and may include
* any of the standard/well-known labels defined by the <tt>LABEL_XXX</tt>
* constants of the <tt>ContactDetail</tt> class. For the sake of
* convenience, <tt>null</tt> and duplicate values in the specified
* <tt>String[]</tt> <tt>labels</tt> will be ignored i.e. will not appear in
* the set of labels reported by the new <tt>ContactDetail</tt> instance
* later on.
*/
public ContactDetail(
String contactAddress,
String category, String[] labels)
{
// contactAddress
this.contactAddress = contactAddress;
// category
this.category = category;
// labels
if (labels != null)
{
for (String label : labels)
{
if ((label != null) && !this.labels.contains(label))
this.labels.add(label);
}
}
}
/**
@ -336,23 +415,25 @@ public void setSupportedOpSets(
* @return the category of this <tt>ContactQuery</tt> if it has any;
* otherwise, <tt>null</tt>
*/
public String getCategory()
public Category getCategory()
{
return category;
}
/**
* Returns the contact address corresponding to this detail.
*
* @return the contact address corresponding to this detail
*/
public String getContactAddress()
public String getDetail()
{
return contactAddress;
return contactDetailValue;
}
/**
* Returns the preferred <tt>ProtocolProviderService</tt> when using the
* given <tt>opSetClass</tt>.
*
* @param opSetClass the <tt>OperationSet</tt> class corresponding to a
* certain action (e.g. sending an instant message, making a call, etc.).
* @return the preferred <tt>ProtocolProviderService</tt> corresponding to
@ -412,9 +493,9 @@ public List<Class<? extends OperationSet>> getSupportedOperationSets()
* @return <tt>true</tt> if the specified <tt>label</tt> is contained in the
* set of labels of this <tt>ContactDetail</tt>
*/
public boolean containsLabel(String label)
public boolean containsSubCategory(SubCategory label)
{
return labels.contains(label);
return subCategories.contains(label);
}
/**
@ -426,8 +507,8 @@ public boolean containsLabel(String label)
* <tt>ContactDetail</tt> has no labels, the returned <tt>Collection</tt> is
* empty.
*/
public Collection<String> getLabels()
public Collection<SubCategory> getSubCategories()
{
return Collections.unmodifiableCollection(labels);
return Collections.unmodifiableCollection(subCategories);
}
}

@ -0,0 +1,59 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.contactsource;
/**
* The <tt>EditableContactDetail</tt> is a <tt>ContactDetail</tt> that allows
* editing.
*
* @see ContactDetail
*
* @author Yana Stamcheva
*/
public class EditableContactDetail
extends ContactDetail
{
/**
* Creates a <tt>ContactDetail</tt> by specifying the contact address,
* corresponding to this detail.
* @param contactDetailValue the contact detail value corresponding to this
* detail
*/
public EditableContactDetail(String contactDetailValue)
{
super(contactDetailValue);
}
/**
* Initializes a new <tt>ContactDetail</tt> instance which is to represent a
* specific contact address and which is to be optionally labeled with a
* specific set of labels.
*
* @param contactDetailValue the contact detail value to be represented by
* the new <tt>ContactDetail</tt> instance
* @param category
* @param subCategories the set of sub categories with which the new
* <tt>ContactDetail</tt> instance is to be labeled.
*/
public EditableContactDetail(
String contactDetailValue,
ContactDetail.Category category,
ContactDetail.SubCategory[] subCategories)
{
super(contactDetailValue, category, subCategories);
}
/**
* Sets the given detail value.
*
* @param value the new value of the detail
*/
public void setDetail(String value)
{
contactDetailValue = value;
}
}

@ -0,0 +1,34 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.contactsource;
/**
* The <tt>EditableSourceContact</tt> is an extension to the
* <tt>SourceContact</tt> interface that allows editing.
*
* @see SourceContact
*
* @author Yana Stamcheva
*/
public interface EditableSourceContact
extends SourceContact
{
/**
* Adds a contact detail to the list of contact details.
*
* @param detail the <tt>ContactDetail</tt> to add
*/
public void addContactDetail(ContactDetail detail);
/**
* Removes the given <tt>ContactDetail</tt> from the list of details for
* this <tt>SourceContact</tt>.
*
* @param detail the <tt>ContactDetail</tt> to remove
*/
public void removeContactDetail(ContactDetail detail);
}

@ -115,13 +115,14 @@ public List<ContactDetail> getContactDetails(
* @return a list of all <tt>ContactDetail</tt>s corresponding to the given
* category
*/
public List<ContactDetail> getContactDetails(String category)
public List<ContactDetail> getContactDetails(
ContactDetail.Category category)
{
List<ContactDetail> contactDetails = new LinkedList<ContactDetail>();
for (ContactDetail contactDetail : getContactDetails())
{
String detailCategory = contactDetail.getCategory();
ContactDetail.Category detailCategory = contactDetail.getCategory();
if (detailCategory != null && detailCategory.equals(category))
contactDetails.add(contactDetail);
}

@ -70,7 +70,8 @@ public List<ContactDetail> getContactDetails(
* @throws OperationNotSupportedException if categories aren't supported
* for call history records
*/
public List<ContactDetail> getContactDetails(String category)
public List<ContactDetail> getContactDetails(
ContactDetail.Category category)
throws OperationNotSupportedException;
/**

Loading…
Cancel
Save