/*
* 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.util.call;
import java.util.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.OperationSetServerStoredContactInfo.DetailsResponseListener;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.MobilePhoneDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.VideoDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.WorkPhoneDetail;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.account.*;
/**
* Utility class used to check if there is a telephony service, video calls and
* desktop sharing enabled for a protocol specific <tt>MetaContact</tt>.
*
* @author Damian Minkov
* @author Yana Stamcheva
*/
public class MetaContactPhoneUtil
{
/**
* The metacontcat we are working on.
*/
private MetaContact metaContact;
/**
* The phones that have been discovered for metacontact child contacts.
*/
private Hashtable<Contact,List<String>> phones =
new Hashtable<Contact, List<String>>();
/**
* The video phones that have been discovered
* for metacontact child contacts.
*/
private Hashtable<Contact,List<String>> videoPhones =
new Hashtable<Contact, List<String>>();
/**
* True if there is any phone found for the metacontact.
*/
private boolean hasPhones = false;
/**
* True if there is any video phone found for the metacontact.
*/
private boolean hasVideoDetail = false;
/**
* Is routing for video enabled for any of the contacts of the metacontact.
*/
private boolean routingForVideoEnabled = false;
/**
* Is routing for desktop enabled for any of the contacts of the metacontact.
*/
private boolean routingForDesktopEnabled = false;
/**
* Obtains the util for <tt>metaContact</tt>
* @param metaContact the metaconctact.
* @return ContactPhoneUtil for the <tt>metaContact</tt>.
*/
public static MetaContactPhoneUtil getPhoneUtil(MetaContact metaContact)
{
return new MetaContactPhoneUtil(metaContact);
}
/**
* Creates utility instance for <tt>metaContact</tt>.
* @param metaContact the metacontact checked in the utility.
*/
protected MetaContactPhoneUtil(MetaContact metaContact)
{
this.metaContact = metaContact;
}
/**
* Returns the metaContact we work on.
* @return the metaContact we work on.
*/
public MetaContact getMetaContact()
{
return metaContact;
}
/**
* Returns localized addition phones list for contact, if any.
* Return null if we have stopped searching and a listener is available
* and will be used to inform for results.
* @param contact the contact
* @return localized addition phones list for contact, if any.
*/
public List<String> getPhones(Contact contact)
{
return getPhones(contact, null, true);
}
/**
* Returns list of video phones for <tt>contact</tt>, localized.
* Return null if we have stopped searching and a listener is available
* and will be used to inform for results.
* @param contact the contact to check for video phones.
* @param listener the <tt>DetailsResponseListener</tt> to listen for result
* details
* @return list of video phones for <tt>contact</tt>, localized.
*/
public List<String> getVideoPhones( Contact contact,
DetailsResponseListener listener)
{
if(!this.metaContact.containsContact(contact))
{
return new ArrayList<String>();
}
if(videoPhones.containsKey(contact))
{
return videoPhones.get(contact);
}
List<String> phonesList = ContactPhoneUtil.getContactAdditionalPhones(
contact, listener, true, true);
if(phonesList == null)
return null;
else if (phonesList.size() > 0)
hasVideoDetail = true;
videoPhones.put(contact, phonesList);
// to check for routingForVideoEnabled prop
isVideoCallEnabled(contact);
// to check for routingForDesktopEnabled prop
isDesktopSharingEnabled(contact);
return phonesList;
}
/**
* List of phones for contact, localized if <tt>localized</tt> is
* <tt>true</tt>, and not otherwise.
* Return null if we have stopped searching and a listener is available
* and will be used to inform for results.
* @param contact the contact to check for video phones.
* @param listener the <tt>DetailsResponseListener</tt> to listen for result
* details
* @param localized whether to localize the phones, put a description text.
* @return list of phones for contact.
*/
public List<String> getPhones( Contact contact,
DetailsResponseListener listener,
boolean localized)
{
if(!this.metaContact.containsContact(contact))
{
return new ArrayList<String>();
}
if(phones.containsKey(contact))
{
return phones.get(contact);
}
List<String> phonesList
= ContactPhoneUtil.getContactAdditionalPhones(
contact, listener, false, localized);
if(phonesList == null)
return null;
else if (phonesList.size() > 0)
hasPhones = true;
phones.put(contact, phonesList);
return phonesList;
}
/**
* Is video called is enabled for metaContact. If any of the child
* contacts has video enabled.
*
* @param listener the <tt>DetailsResponseListener</tt> to listen for result
* details
* @return is video called is enabled for metaContact.
*/
public boolean isVideoCallEnabled(DetailsResponseListener listener)
{
// make sure children are checked
if(!checkMetaContactVideoPhones(listener))
return false;
return metaContact.getDefaultContact(
OperationSetVideoTelephony.class) != null
|| routingForVideoEnabled
|| hasVideoDetail;
}
/**
* Is video called is enabled for metaContact. If any of the child
* contacts has video enabled.
*
* @return is video called is enabled for metaContact.
*/
public boolean isVideoCallEnabled()
{
return isVideoCallEnabled((DetailsResponseListener) null);
}
/**
* Is video call enabled for contact.
* @param contact to check for video capabilities.
* @return is video call enabled for contact.
*/
public boolean isVideoCallEnabled(Contact contact)
{
if(!this.metaContact.containsContact(contact))
return false;
// make sure we have checked everything for the contact
// before continue
if(!checkContactPhones(contact))
return false;
routingForVideoEnabled =
ConfigurationUtils
.isRouteVideoAndDesktopUsingPhoneNumberEnabled()
&& phones.containsKey(contact)
&& phones.get(contact).size() > 0
&& AccountUtils.getOpSetRegisteredProviders(
OperationSetVideoTelephony.class,
null,
null).size() > 0;
return contact.getProtocolProvider().getOperationSet(
OperationSetVideoTelephony.class) != null
&& hasContactCapabilities(contact,
OperationSetVideoTelephony.class)
|| routingForVideoEnabled;
}
/**
* Is desktop sharing enabled for metaContact. If any of the child
* contacts has desktop sharing enabled.
* @param listener the <tt>DetailsResponseListener</tt> to listen for result
* details
* @return is desktop share is enabled for metaContact.
*/
public boolean isDesktopSharingEnabled(DetailsResponseListener listener)
{
// make sure children are checked
if(!checkMetaContactVideoPhones(listener))
return false;
return metaContact.getDefaultContact(
OperationSetDesktopSharingServer.class) != null
|| routingForDesktopEnabled
|| hasVideoDetail;
}
/**
* Is desktop sharing enabled for metaContact. If any of the child
* contacts has desktop sharing enabled.
* @return is desktop share is enabled for metaContact.
*/
public boolean isDesktopSharingEnabled()
{
return isDesktopSharingEnabled((DetailsResponseListener) null);
}
/**
* Is desktop sharing enabled for contact.
* @param contact to check for desktop sharing capabilities.
* @return is desktop sharing enabled for contact.
*/
public boolean isDesktopSharingEnabled(Contact contact)
{
if(!this.metaContact.containsContact(contact))
return false;
// make sure we have checked everything for the contact
// before continue
if(!checkContactPhones(contact))
return false;
routingForDesktopEnabled =
ConfigurationUtils
.isRouteVideoAndDesktopUsingPhoneNumberEnabled()
&& phones.containsKey(contact)
&& phones.get(contact).size() > 0
&& AccountUtils.getOpSetRegisteredProviders(
OperationSetDesktopSharingServer.class,
null,
null).size() > 0;
return contact.getProtocolProvider().getOperationSet(
OperationSetDesktopSharingServer.class) != null
&& hasContactCapabilities(contact,
OperationSetDesktopSharingServer.class)
|| routingForDesktopEnabled;
}
/**
* Is call enabled for metaContact. If any of the child
* contacts has call enabled.
* @param listener the <tt>DetailsResponseListener</tt> to listen for result
* details
* @return is call enabled for metaContact.
*/
public boolean isCallEnabled(DetailsResponseListener listener)
{
return isCallEnabled(listener, true);
}
/**
* Is call enabled for metaContact. If any of the child
* contacts has call enabled.
* @param listener the <tt>DetailsResponseListener</tt> to listen for result
* details
* @param checkForTelephonyOpSet whether we should check for registered
* telephony operation sets that can be used to dial out, can be used
* in plugins dialing out using methods outside the provider.
* @return is call enabled for metaContact.
*/
public boolean isCallEnabled(DetailsResponseListener listener,
boolean checkForTelephonyOpSet)
{
// make sure children are checked
if(!checkMetaContactPhones(listener))
return false;
boolean hasPhoneCheck = hasPhones;
if(checkForTelephonyOpSet)
hasPhoneCheck =
hasPhones && AccountUtils.getRegisteredProviders(
OperationSetBasicTelephony.class).size() > 0;
return metaContact.getDefaultContact(
OperationSetBasicTelephony.class) != null
|| hasPhoneCheck;
}
/**
* Is call enabled for metaContact. If any of the child
* contacts has call enabled.
* @return is call enabled for metaContact.
*/
public boolean isCallEnabled()
{
return isCallEnabled(null, true);
}
/**
* Is call enabled for metaContact. If any of the child
* contacts has call enabled.
* @param checkForTelephonyOpSet whether we should check for registered
* telephony operation sets that can be used to dial out, can be used
* in plugins dialing out using methods outside the provider.
* @return is call enabled for metaContact.
*/
public boolean isCallEnabled(boolean checkForTelephonyOpSet)
{
return isCallEnabled(null,
checkForTelephonyOpSet);
}
/**
* Is call enabled for contact.
* @param contact to check for call capabilities.
* @return is call enabled for contact.
*/
public boolean isCallEnabled(Contact contact)
{
if(!checkContactPhones(contact))
return false;
return contact.getProtocolProvider().getOperationSet(
OperationSetBasicTelephony.class) != null
&& hasContactCapabilities(contact,
OperationSetBasicTelephony.class);
}
/**
* Checking all contacts for the metacontact.
* Return <tt>false</tt> if there are listeners added for a contact
* and we need to stop executions cause listener will be used to be informed
* for result.
*
* @return whether to continue or listeners present and will be informed
* for result.
*/
private boolean checkMetaContactPhones()
{
return checkMetaContactPhones(null);
}
/**
* Checking all contacts for the metacontact.
* Return <tt>false</tt> if there are listeners added for a contact
* and we need to stop executions cause listener will be used to be informed
* for result.
*
* @param l the <tt>DetailsResponseListener</tt> to listen for further
* details
* @return whether to continue or listeners present and will be informed
* for result.
*/
private boolean checkMetaContactPhones(DetailsResponseListener l)
{
Iterator<Contact> contactIterator = metaContact.getContacts();
while(contactIterator.hasNext())
{
Contact contact = contactIterator.next();
if(phones.containsKey(contact))
continue;
List<String> phones = getPhones(contact, l, false);
if(phones == null)
return false;
}
return true;
}
/**
* Checking all contacts for the metacontact.
* Return <tt>false</tt> if there are listeners added for a contact
* and we need to stop executions cause listener will be used to be informed
* for result.
*
* @param l the <tt>DetailsResponseListener</tt> to listen for further
* details
* @return whether to continue or listeners present and will be informed
* for result.
*/
private boolean checkMetaContactVideoPhones(DetailsResponseListener l)
{
Iterator<Contact> contactIterator = metaContact.getContacts();
while(contactIterator.hasNext())
{
Contact contact = contactIterator.next();
if(videoPhones.containsKey(contact))
continue;
List<String> phones = getVideoPhones(contact, l);
if(phones == null)
return false;
}
return true;
}
/**
* Checking contact for phones.
* Return <tt>false</tt> if there are listeners added for the contact
* and we need to stop executions cause listener will be used to be informed
* for result.
*
* @return whether to continue or listeners present and will be informed
* for result.
*/
private boolean checkContactPhones(Contact contact)
{
if(!phones.containsKey(contact))
{
List<String> phones = getPhones(contact);
if(phones == null)
return false;
// to check for routingForVideoEnabled prop
isVideoCallEnabled(contact);
// to check for routingForDesktopEnabled prop
isDesktopSharingEnabled(contact);
}
return true;
}
/**
* Returns <tt>true</tt> if <tt>Contact</tt> supports the specified
* <tt>OperationSet</tt>, <tt>false</tt> otherwise.
*
* @param contact contact to check
* @param opSet <tt>OperationSet</tt> to search for
* @return Returns <tt>true</tt> if <tt>Contact</tt> supports the specified
* <tt>OperationSet</tt>, <tt>false</tt> otherwise.
*/
private boolean hasContactCapabilities(
Contact contact, Class<? extends OperationSet> opSet)
{
OperationSetContactCapabilities capOpSet =
contact.getProtocolProvider().
getOperationSet(OperationSetContactCapabilities.class);
if (capOpSet == null)
{
// assume contact has OpSet capabilities
return true;
}
else
{
if(capOpSet.getOperationSet(contact, opSet) != null)
{
return true;
}
}
return false;
}
/**
* Returns localized phone number.
*
* @param d the detail.
* @return the localized phone number.
*/
protected String getLocalizedPhoneNumber(GenericDetail d)
{
if(d instanceof WorkPhoneDetail)
{
return UtilActivator.getResources().
getI18NString(
"service.gui.WORK_PHONE");
}
else if(d instanceof MobilePhoneDetail)
{
return UtilActivator.getResources().
getI18NString(
"service.gui.MOBILE_PHONE");
}
else if(d instanceof VideoDetail)
{
return UtilActivator.getResources().
getI18NString(
"service.gui.VIDEO_PHONE");
}
else
{
return UtilActivator.getResources().
getI18NString(
"service.gui.HOME");
}
}
}