/*
* 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.service.protocol;
import java.util.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
* An Abstract Operation Set defining option to unconditionally auto answer
* incoming calls.
*
* @author Damian Minkov
* @author Vincent Lucas
*/
public abstract class AbstractOperationSetBasicAutoAnswer
implements OperationSetBasicAutoAnswer
{
/**
* Our class logger.
*/
private static final Logger logger
= Logger.getLogger(AbstractOperationSetBasicAutoAnswer.class);
/**
* The parent Protocol Provider.
*/
protected final ProtocolProviderService protocolProvider;
/**
* Should we unconditionally answer.
*/
protected boolean answerUnconditional = false;
/**
* Should we answer video calls with video.
*/
protected boolean answerWithVideo = false;
/**
* Creates this operation set, loads stored values, populating
* local variable settings.
*
* @param protocolProvider the parent Protocol Provider.
*/
public AbstractOperationSetBasicAutoAnswer(
ProtocolProviderService protocolProvider)
{
this.protocolProvider = protocolProvider;
}
/**
* Load values from account properties.
*/
protected void load()
{
AccountID acc = protocolProvider.getAccountID();
answerUnconditional
= acc.getAccountPropertyBoolean(AUTO_ANSWER_UNCOND_PROP, false);
answerWithVideo
= acc.getAccountPropertyBoolean(AUTO_ANSWER_WITH_VIDEO_PROP, false);
}
/**
* Saves values to account properties.
*/
protected abstract void save();
/**
* Clear local settings.
*/
protected void clearLocal()
{
this.answerUnconditional = false;
}
/**
* Clear any previous settings.
*/
public void clear()
{
clearLocal();
this.answerWithVideo = false;
save();
}
/**
* Makes a check after creating call locally, should we answer it.
*
* @param call The new incoming call to auto-answer if needed.
* @param isVideoCall Indicates if the remote peer which has created this
* call wish to have a video call.
*
* @return <tt>true</tt> if we have processed and no further processing is
* needed, <tt>false</tt> otherwise.
*/
public boolean autoAnswer(Call call, boolean isVideoCall)
{
if(answerUnconditional || satisfyAutoAnswerConditions(call))
{
this.answerCall(call, isVideoCall);
return true;
}
return false;
}
/**
* Answers call if peer in correct state or wait for it.
*
* @param call The new incoming call to auto-answer if needed.
* @param isVideoCall Indicates if the remote peer which has created this
* call wish to have a video call.
*/
protected void answerCall(Call call, boolean isVideoCall)
{
// We are here because we satisfy the conditional, or unconditional is
// true.
Iterator<? extends CallPeer> peers = call.getCallPeers();
while (peers.hasNext())
{
new AutoAnswerThread(peers.next(), isVideoCall);
}
}
/**
* Checks if the call satisfy the auto answer conditions.
*
* @param call The new incoming call to auto-answer if needed.
*
* @return <tt>true</tt> if the call satisfy the auto answer conditions.
* <tt>False</tt> otherwise.
*/
protected abstract boolean satisfyAutoAnswerConditions(Call call);
/**
* Sets the auto answer option to unconditionally answer all incoming calls.
*/
public void setAutoAnswerUnconditional()
{
clearLocal();
this.answerUnconditional = true;
save();
}
/**
* Is the auto answer option set to unconditionally
* answer all incoming calls.
*
* @return is auto answer set to unconditional.
*/
public boolean isAutoAnswerUnconditionalSet()
{
return answerUnconditional;
}
/**
* Sets the auto answer with video to video calls.
*
* @param answerWithVideo A boolean set to true to activate the auto answer
* with video when receiving a video call. False otherwise.
*/
public void setAutoAnswerWithVideo(boolean answerWithVideo)
{
this.answerWithVideo = answerWithVideo;
this.save();
}
/**
* Returns if the auto answer with video to video calls is activated.
*
* @return A boolean set to true if the auto answer with video when
* receiving a video call is activated. False otherwise.
*/
public boolean isAutoAnswerWithVideoSet()
{
return this.answerWithVideo;
}
/**
* Waits for peer to switch into INCOMING_CALL state, before
* auto-answering the call in a new thread.
*/
private class AutoAnswerThread
extends CallPeerAdapter
implements Runnable
{
/**
* The call peer which has generated the call.
*/
private CallPeer peer;
/**
* Indicates if the remote peer which has created this call wish to have
* a video call.
*/
private boolean isVideoCall;
/**
* Waits for peer to switch into INCOMING_CALL state, before
* auto-answering the call in a new thread.
*
* @param peer The call peer which has generated the call.
* @param isVideoCall Indicates if the remote peer which has created
* this call wish to have a video call.
*/
public AutoAnswerThread(CallPeer peer, boolean isVideoCall)
{
this.peer = peer;
this.isVideoCall = isVideoCall;
if (peer.getState() == CallPeerState.INCOMING_CALL)
{
new Thread(this).start();
}
else
{
peer.addCallPeerListener(this);
}
}
/**
* Answers the call.
*/
public void run()
{
OperationSetBasicTelephony<?> opSetBasicTelephony
= protocolProvider.getOperationSet(
OperationSetBasicTelephony.class);
OperationSetVideoTelephony opSetVideoTelephony
= protocolProvider.getOperationSet(
OperationSetVideoTelephony.class);
try
{
// If this is a video call and that the user has configured to
// answer it with video, then create a video call.
if(this.isVideoCall
&& answerWithVideo
&& opSetVideoTelephony != null)
{
opSetVideoTelephony.answerVideoCallPeer(peer);
}
// Else sends only audio to the remote peer (the remote peer is
// still able to send us its video stream).
else if(opSetBasicTelephony != null)
{
opSetBasicTelephony.answerCallPeer(peer);
}
}
catch (OperationFailedException e)
{
logger.error("Could not answer to : " + peer
+ " caused by the following exception: " + e);
}
}
/**
* If we peer was not in proper state wait for it and then answer.
*
* @param evt the <tt>CallPeerChangeEvent</tt> instance containing the
*/
@Override
public void peerStateChanged(CallPeerChangeEvent evt)
{
CallPeerState newState = (CallPeerState) evt.getNewValue();
if (newState == CallPeerState.INCOMING_CALL)
{
evt.getSourceCallPeer().removeCallPeerListener(this);
new Thread(this).start();
}
else if (newState == CallPeerState.DISCONNECTED
|| newState == CallPeerState.FAILED)
{
evt.getSourceCallPeer().removeCallPeerListener(this);
}
}
}
}