Fixed normal bug EXT-4301 (PDD: Dial-in to a PSTN bridge shows "(???) (???)" for the name.)

* Implementation notes:
** special item is cloned from VCP to be used in LLAvatarList to reflect an Avaline caller.
** LLAvatarList extended to create instances of Avaline Caller
** Participant list now determines type of adding session participant (Avatar/Avaline Caller) and selects a way item will be created in avatar list

* Implementation behavior:
** The problem is when Avaline caller ends a call it is removed from Voice Client session but
   still exists in LLSpeakerMgr. Server does not send such information.
   HUCK was implemented to notify subscribers that Avaline callers are not anymore in the voice call.
** For now Avaline Caller is removed from the LLSpeakerMgr List when it is removed from the Voice Client session.
   This happens in two cases: if Avaline Caller ends call itself or if Resident ends group call.

** If Resident joins group call where Avaline caller already exists that caller will appear in Resident's viewer (VCP & Group IM window)
** The callers are displayed as "AvaLine Caller 1", "AvaLine Caller 2" etc.

* Known issues:
** LLNonAvatarCaller should be removed from VCP (for avaline p2p calls). Updated Avatar & Participant Lists can be used instead of it.
    Separate ticket will be opened to refactor this code.

--HG--
branch : product-engine
meow-7.2.2
Mike Antipov 2010-04-14 12:17:47 +03:00
parent 93317037ee
commit 5e34a91ce6
8 changed files with 332 additions and 7 deletions

View File

@ -32,13 +32,18 @@
#include "llviewerprecompiledheaders.h"
// common
#include "lltrans.h"
#include "llavatarlist.h"
#include "llagentdata.h" // for comparator
// newview
#include "llavatariconctrl.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcachename.h"
#include "llrecentpeople.h"
#include "lltextutil.h"
#include "lluuid.h"
#include "llvoiceclient.h"
#include "llviewercontrol.h" // for gSavedSettings
@ -193,6 +198,18 @@ void LLAvatarList::setDirty(bool val /*= true*/, bool force_refresh /*= false*/)
}
}
void LLAvatarList::addAvalineItem(const LLUUID& item_id, const LLUUID& session_id, const std::string& item_name)
{
LL_DEBUGS("Avaline") << "Adding avaline item into the list: " << item_name << "|" << item_id << ", session: " << session_id << LL_ENDL;
LLAvalineListItem* item = new LLAvalineListItem;
item->setAvatarId(item_id, session_id, true, false);
item->setName(item_name);
addItem(item, item_id);
mIDs.push_back(item_id);
sort();
}
//////////////////////////////////////////////////////////////////////////
// PROTECTED SECTION
//////////////////////////////////////////////////////////////////////////
@ -471,3 +488,61 @@ bool LLAvatarItemAgentOnTopComparator::doCompare(const LLAvatarListItem* avatar_
}
return LLAvatarItemNameComparator::doCompare(avatar_item1,avatar_item2);
}
/************************************************************************/
/* class LLAvalineListItem */
/************************************************************************/
LLAvalineListItem::LLAvalineListItem(bool hide_number/* = true*/) : LLAvatarListItem(false)
, mIsHideNumber(hide_number)
{
// should not use buildPanel from the base class to ensure LLAvalineListItem::postBuild is called.
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_list_item.xml");
}
BOOL LLAvalineListItem::postBuild()
{
BOOL rv = LLAvatarListItem::postBuild();
if (rv)
{
setOnline(true);
showLastInteractionTime(false);
setShowProfileBtn(false);
setShowInfoBtn(false);
mAvatarIcon->setValue("Avaline_Icon");
mAvatarIcon->setToolTip(std::string(""));
}
return rv;
}
// to work correctly this method should be called AFTER setAvatarId for avaline callers with hidden phone number
void LLAvalineListItem::setName(const std::string& name)
{
if (mIsHideNumber)
{
static U32 order = 0;
typedef std::map<LLUUID, U32> avaline_callers_nums_t;
static avaline_callers_nums_t mAvalineCallersNums;
llassert(getAvatarId() != LLUUID::null);
const LLUUID &uuid = getAvatarId();
if (mAvalineCallersNums.find(uuid) == mAvalineCallersNums.end())
{
mAvalineCallersNums[uuid] = ++order;
LL_DEBUGS("Avaline") << "Set name for new avaline caller: " << uuid << ", order: " << order << LL_ENDL;
}
LLStringUtil::format_map_t args;
args["[ORDER]"] = llformat("%u", mAvalineCallersNums[uuid]);
std::string hidden_name = LLTrans::getString("AvalineCaller", args);
LL_DEBUGS("Avaline") << "Avaline caller: " << uuid << ", name: " << hidden_name << LL_ENDL;
LLAvatarListItem::setName(hidden_name);
}
else
{
const std::string& formatted_phone = LLTextUtil::formatPhoneNumber(name);
LLAvatarListItem::setName(formatted_phone);
}
}

View File

@ -96,6 +96,8 @@ public:
virtual S32 notifyParent(const LLSD& info);
void addAvalineItem(const LLUUID& item_id, const LLUUID& session_id, const std::string& item_name);
protected:
void refresh();
@ -175,4 +177,27 @@ protected:
virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const;
};
/**
* Represents Avaline caller in Avatar list in Voice Control Panel and group chats.
*/
class LLAvalineListItem : public LLAvatarListItem
{
public:
/**
* Constructor
*
* @param hide_number - flag indicating if number should be hidden.
* In this case It will be shown as "Avaline Caller 1", "Avaline Caller 1", etc.
*/
LLAvalineListItem(bool hide_number = true);
/*virtual*/ BOOL postBuild();
/*virtual*/ void setName(const std::string& name);
private:
bool mIsHideNumber;
};
#endif // LL_LLAVATARLIST_H

View File

@ -212,21 +212,25 @@ void LLAvatarListItem::setState(EItemState item_style)
mAvatarIcon->setColor(item_icon_color_map[item_style]);
}
void LLAvatarListItem::setAvatarId(const LLUUID& id, const LLUUID& session_id, bool ignore_status_changes)
void LLAvatarListItem::setAvatarId(const LLUUID& id, const LLUUID& session_id, bool ignore_status_changes/* = false*/, bool is_resident/* = true*/)
{
if (mAvatarId.notNull())
LLAvatarTracker::instance().removeParticularFriendObserver(mAvatarId, this);
mAvatarId = id;
mAvatarIcon->setValue(id);
mSpeakingIndicator->setSpeakerId(id, session_id);
// We'll be notified on avatar online status changes
if (!ignore_status_changes && mAvatarId.notNull())
LLAvatarTracker::instance().addParticularFriendObserver(mAvatarId, this);
// Set avatar name.
gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));
if (is_resident)
{
mAvatarIcon->setValue(id);
// Set avatar name.
gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));
}
}
void LLAvatarListItem::showLastInteractionTime(bool show)

View File

@ -100,7 +100,7 @@ public:
void setName(const std::string& name);
void setHighlight(const std::string& highlight);
void setState(EItemState item_style);
void setAvatarId(const LLUUID& id, const LLUUID& session_id, bool ignore_status_changes = false);
void setAvatarId(const LLUUID& id, const LLUUID& session_id, bool ignore_status_changes = false, bool is_resident = true);
void setLastInteractionTime(U32 secs_since);
//Show/hide profile/info btn, translating speaker indicator and avatar name coordinates accordingly
void setShowProfileBtn(bool show);

View File

@ -50,6 +50,145 @@
static const LLAvatarItemAgentOnTopComparator AGENT_ON_TOP_NAME_COMPARATOR;
// See EXT-4301.
/**
* class LLAvalineUpdater - observe the list of voice participants in session and check
* presence of Avaline Callers among them.
*
* LLAvalineUpdater is a LLVoiceClientParticipantObserver. It provides two kinds of validation:
* - whether Avaline caller presence among participants;
* - whether watched Avaline caller still exists in voice channel.
* Both validations have callbacks which will notify subscriber if any of event occur.
*
* @see findAvalineCaller()
* @see checkIfAvalineCallersExist()
*/
class LLAvalineUpdater : public LLVoiceClientParticipantObserver
{
public:
typedef boost::function<void(const LLUUID& speaker_id)> process_avaline_callback_t;
LLAvalineUpdater(process_avaline_callback_t found_cb, process_avaline_callback_t removed_cb)
: mAvalineFoundCallback(found_cb)
, mAvalineRemovedCallback(removed_cb)
{
LLVoiceClient::getInstance()->addObserver(this);
}
~LLAvalineUpdater()
{
if (LLVoiceClient::instanceExists())
{
LLVoiceClient::getInstance()->removeObserver(this);
}
}
/**
* Adds UUID of Avaline caller to watch.
*
* @see checkIfAvalineCallersExist().
*/
void watchAvalineCaller(const LLUUID& avaline_caller_id)
{
mAvalineCallers.insert(avaline_caller_id);
}
void onChange()
{
uuid_set_t participant_uuids;
LLVoiceClient::getInstance()->getParticipantsUUIDSet(participant_uuids);
// check whether Avaline caller exists among voice participants
// and notify Participant List
findAvalineCaller(participant_uuids);
// check whether watched Avaline callers still present among voice participant
// and remove if absents.
checkIfAvalineCallersExist(participant_uuids);
}
private:
typedef std::set<LLUUID> uuid_set_t;
/**
* Finds Avaline callers among voice participants and calls mAvalineFoundCallback.
*
* When Avatar is in group call with Avaline caller and then ends call Avaline caller stays
* in Group Chat floater (exists in LLSpeakerMgr). If Avatar starts call with that group again
* Avaline caller is added to voice channel AFTER Avatar is connected to group call.
* But Voice Control Panel (VCP) is filled from session LLSpeakerMgr and there is no information
* if a speaker is Avaline caller.
*
* In this case this speaker is created as avatar and will be recreated when it appears in
* Avatar's Voice session.
*
* @see LLParticipantList::onAvalineCallerFound()
*/
void findAvalineCaller(const uuid_set_t& participant_uuids)
{
uuid_set_t::const_iterator it = participant_uuids.begin(), it_end = participant_uuids.end();
for(; it != it_end; ++it)
{
const LLUUID& participant_id = *it;
if (!LLVoiceClient::getInstance()->isParticipantAvatar(participant_id))
{
LL_DEBUGS("Avaline") << "Avaline caller found among voice participants: " << participant_id << LL_ENDL;
if (mAvalineFoundCallback)
{
mAvalineFoundCallback(participant_id);
}
}
}
}
/**
* Finds Avaline callers which are not anymore among voice participants and calls mAvalineRemovedCallback.
*
* The problem is when Avaline caller ends a call it is removed from Voice Client session but
* still exists in LLSpeakerMgr. Server does not send such information.
* This method implements a HUCK to notify subscribers that watched Avaline callers by class
* are not anymore in the call.
*
* @see LLParticipantList::onAvalineCallerRemoved()
*/
void checkIfAvalineCallersExist(const uuid_set_t& participant_uuids)
{
uuid_set_t::iterator it = mAvalineCallers.begin();
uuid_set_t::const_iterator participants_it_end = participant_uuids.end();
while (it != mAvalineCallers.end())
{
const LLUUID participant_id = *it;
LL_DEBUGS("Avaline") << "Check avaline caller: " << participant_id << LL_ENDL;
bool not_found = participant_uuids.find(participant_id) == participants_it_end;
if (not_found)
{
LL_DEBUGS("Avaline") << "Watched Avaline caller is not found among voice participants: " << participant_id << LL_ENDL;
// notify Participant List
if (mAvalineRemovedCallback)
{
mAvalineRemovedCallback(participant_id);
}
// remove from the watch list
mAvalineCallers.erase(it++);
}
else
{
++it;
}
}
}
process_avaline_callback_t mAvalineFoundCallback;
process_avaline_callback_t mAvalineRemovedCallback;
uuid_set_t mAvalineCallers;
};
LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list, bool use_context_menu/* = true*/,
bool exclude_agent /*= true*/, bool can_toggle_icons /*= true*/):
mSpeakerMgr(data_source),
@ -59,6 +198,9 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av
, mExcludeAgent(exclude_agent)
, mValidateSpeakerCallback(NULL)
{
mAvalineUpdater = new LLAvalineUpdater(boost::bind(&LLParticipantList::onAvalineCallerFound, this, _1),
boost::bind(&LLParticipantList::onAvalineCallerRemoved, this, _1));
mSpeakerAddListener = new SpeakerAddListener(*this);
mSpeakerRemoveListener = new SpeakerRemoveListener(*this);
mSpeakerClearListener = new SpeakerClearListener(*this);
@ -137,6 +279,9 @@ LLParticipantList::~LLParticipantList()
}
mAvatarList->setContextMenu(NULL);
mAvatarList->setComparator(NULL);
delete mAvalineUpdater;
}
void LLParticipantList::setSpeakingIndicatorsVisible(BOOL visible)
@ -210,6 +355,55 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param)
}
}
/*
Seems this method is not necessary after onAvalineCallerRemoved was implemented;
It does nothing because list item is always created with correct class type for Avaline caller.
For now Avaline Caller is removed from the LLSpeakerMgr List when it is removed from the Voice Client
session.
This happens in two cases: if Avaline Caller ends call itself or if Resident ends group call.
Probably Avaline caller should be removed from the LLSpeakerMgr list ONLY if it ends call itself.
Asked in EXT-4301.
*/
void LLParticipantList::onAvalineCallerFound(const LLUUID& participant_id)
{
LLPanel* item = mAvatarList->getItemByValue(participant_id);
if (NULL == item)
{
LL_WARNS("Avaline") << "Something wrong. Unable to find item for: " << participant_id << LL_ENDL;
return;
}
if (typeid(*item) == typeid(LLAvalineListItem))
{
LL_DEBUGS("Avaline") << "Avaline caller has already correct class type for: " << participant_id << LL_ENDL;
// item representing an Avaline caller has a correct type already.
return;
}
LL_DEBUGS("Avaline") << "remove item from the list and re-add it: " << participant_id << LL_ENDL;
// remove UUID from LLAvatarList::mIDs to be able add it again.
uuid_vec_t& ids = mAvatarList->getIDs();
uuid_vec_t::iterator pos = std::find(ids.begin(), ids.end(), participant_id);
ids.erase(pos);
// remove item directly
mAvatarList->removeItem(item);
// re-add avaline caller with a correct class instance.
addAvatarIDExceptAgent(participant_id);
}
void LLParticipantList::onAvalineCallerRemoved(const LLUUID& participant_id)
{
LL_DEBUGS("Avaline") << "Removing avaline caller from the list: " << participant_id << LL_ENDL;
mSpeakerMgr->removeAvalineSpeaker(participant_id);
}
void LLParticipantList::setSortOrder(EParticipantSortOrder order)
{
if ( mSortOrder != order )
@ -355,8 +549,20 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
if (mExcludeAgent && gAgent.getID() == avatar_id) return;
if (mAvatarList->contains(avatar_id)) return;
mAvatarList->getIDs().push_back(avatar_id);
mAvatarList->setDirty();
bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(avatar_id);
if (is_avatar)
{
mAvatarList->getIDs().push_back(avatar_id);
mAvatarList->setDirty();
}
else
{
LLVoiceClient::participantState *participant = LLVoiceClient::getInstance()->findParticipantByID(avatar_id);
mAvatarList->addAvalineItem(avatar_id, mSpeakerMgr->getSessionID(), participant ? participant->mAccountName : LLTrans::getString("AvatarNameWaiting"));
mAvalineUpdater->watchAvalineCaller(avatar_id);
}
adjustParticipant(avatar_id);
}

View File

@ -38,6 +38,7 @@
class LLSpeakerMgr;
class LLAvatarList;
class LLUICtrl;
class LLAvalineUpdater;
class LLParticipantList
{
@ -235,6 +236,9 @@ class LLParticipantList
void onAvatarListDoubleClicked(LLUICtrl* ctrl);
void onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param);
void onAvalineCallerFound(const LLUUID& participant_id);
void onAvalineCallerRemoved(const LLUUID& participant_id);
/**
* Adjusts passed participant to work properly.
*
@ -272,4 +276,5 @@ class LLParticipantList
LLPointer<LLAvatarItemRecentSpeakerComparator> mSortByRecentSpeakers;
validate_speaker_callback_t mValidateSpeakerCallback;
LLAvalineUpdater* mAvalineUpdater;
};

View File

@ -234,6 +234,14 @@ public:
LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; }
const LLUUID getSessionID();
/**
* Removes avaline speaker.
*
* This is a HACK due to server does not send information that Avaline caller ends call.
* It can be removed when server is updated. See EXT-4301 for details
*/
bool removeAvalineSpeaker(const LLUUID& speaker_id) { return removeSpeaker(speaker_id); }
protected:
virtual void updateSpeakerList();
void setSpeakerNotInChannel(LLSpeaker* speackerp);

View File

@ -148,6 +148,8 @@
<!-- Group name: text shown for LLUUID::null -->
<string name="GroupNameNone">(none)</string>
<string name="AvalineCaller">Avaline Caller [ORDER]</string>
<!-- Asset errors. Used in llassetstorage.cpp, translation from error code to error message. -->
<string name="AssetErrorNone">No error</string>
<string name="AssetErrorRequestFailed">Asset request: failed</string>