Bug 814625 - Part 4: DOM: Refactor. r=khuey

This commit is contained in:
Szu-Yu Chen [:aknow] 2013-10-31 08:05:51 -04:00
parent b9396ba2d7
commit 7a698c9040
2 changed files with 144 additions and 156 deletions

View File

@ -175,26 +175,58 @@ Telephony::Create(nsPIDOMWindow* aOwner, ErrorResult& aRv)
return telephony.forget();
}
// static
bool
Telephony::IsValidNumber(const nsAString& aNumber)
{
return !aNumber.IsEmpty();
}
// static
bool
Telephony::IsActiveState(uint16_t aCallState) {
return aCallState == nsITelephonyProvider::CALL_STATE_DIALING ||
aCallState == nsITelephonyProvider::CALL_STATE_ALERTING ||
aCallState == nsITelephonyProvider::CALL_STATE_CONNECTED;
}
bool
Telephony::HasDialingCall()
{
for (uint32_t i = 0; i < mCalls.Length(); i++) {
const nsRefPtr<TelephonyCall>& call = mCalls[i];
if (call->IsOutgoing() &&
call->CallState() > nsITelephonyProvider::CALL_STATE_UNKNOWN &&
call->CallState() < nsITelephonyProvider::CALL_STATE_CONNECTED) {
return true;
}
}
return false;
}
bool
Telephony::MatchActiveCall(TelephonyCall* aCall)
{
return (mActiveCall &&
mActiveCall->CallIndex() == aCall->CallIndex());
}
already_AddRefed<TelephonyCall>
Telephony::DialInternal(bool isEmergency,
const nsAString& aNumber,
ErrorResult& aRv)
{
if (aNumber.IsEmpty()) {
if (!IsValidNumber(aNumber)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return nullptr;
}
for (uint32_t index = 0; index < mCalls.Length(); index++) {
const nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
if (tempCall->IsOutgoing() &&
tempCall->CallState() < nsITelephonyProvider::CALL_STATE_CONNECTED) {
// One call has been dialed already and we only support one outgoing call
// at a time.
NS_WARNING("Only permitted to dial one call at a time!");
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
// We only support one outgoing call at a time.
if (HasDialingCall()) {
NS_WARNING("Only permitted to dial one call at a time!");
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
nsresult rv = mProvider->Dial(aNumber, isEmergency);
@ -206,8 +238,8 @@ Telephony::DialInternal(bool isEmergency,
nsRefPtr<TelephonyCall> call = CreateNewDialingCall(aNumber);
// Notify other telephony objects that we just dialed.
for (uint32_t index = 0; index < gTelephonyList->Length(); index++) {
Telephony*& telephony = gTelephonyList->ElementAt(index);
for (uint32_t i = 0; i < gTelephonyList->Length(); i++) {
Telephony*& telephony = gTelephonyList->ElementAt(i);
if (telephony != this) {
nsRefPtr<Telephony> kungFuDeathGrip = telephony;
telephony->NoteDialedCallFromOtherInstance(aNumber);
@ -244,16 +276,11 @@ Telephony::NotifyCallsChanged(TelephonyCall* aCall)
}
void
Telephony::UpdateActiveCall(TelephonyCall* aCall, bool aIsAdding)
Telephony::UpdateActiveCall(TelephonyCall* aCall, bool aIsActive)
{
if (aIsAdding) {
if (aCall->CallState() == nsITelephonyProvider::CALL_STATE_DIALING ||
aCall->CallState() == nsITelephonyProvider::CALL_STATE_ALERTING ||
aCall->CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED) {
NS_ASSERTION(!mActiveCall, "Already have an active call!");
mActiveCall = aCall;
}
} else if (mActiveCall && mActiveCall->CallIndex() == aCall->CallIndex()) {
if (aIsActive) {
mActiveCall = aCall;
} else if (MatchActiveCall(aCall)) {
mActiveCall = nullptr;
}
}
@ -274,32 +301,36 @@ Telephony::GetCall(uint32_t aCallIndex)
return call.forget();
}
bool
Telephony::MoveCall(uint32_t aCallIndex, bool aIsConference)
already_AddRefed<TelephonyCall>
Telephony::GetOutgoingCall()
{
nsRefPtr<TelephonyCall> call;
// Move a call to mGroup.
if (aIsConference) {
call = GetCall(aCallIndex);
if (call) {
RemoveCall(call);
mGroup->AddCall(call);
return true;
for (uint32_t i = 0; i < mCalls.Length(); i++) {
nsRefPtr<TelephonyCall>& tempCall = mCalls[i];
if (tempCall->CallIndex() == kOutgoingPlaceholderCallIndex) {
NS_ASSERTION(!call, "More than one outgoing call not supported!");
NS_ASSERTION(tempCall->CallState() == nsITelephonyProvider::CALL_STATE_DIALING,
"Something really wrong here!");
call = tempCall;
// No break. We will search entire list to ensure only one outgoing call.
}
return false;
}
// Remove a call from mGroup.
call = mGroup->GetCall(aCallIndex);
if (call) {
mGroup->RemoveCall(call);
AddCall(call);
return true;
return call.forget();
}
already_AddRefed<TelephonyCall>
Telephony::GetCallFromEverywhere(uint32_t aCallIndex)
{
nsRefPtr<TelephonyCall> call = GetCall(aCallIndex);
if (!call) {
call = mGroup->GetCall(aCallIndex);
}
return false;
return call.forget();
}
NS_IMPL_CYCLE_COLLECTION_CLASS(Telephony)
@ -444,116 +475,70 @@ Telephony::CallStateChanged(uint32_t aCallIndex, uint16_t aCallState,
NS_ASSERTION(aCallIndex != kOutgoingPlaceholderCallIndex,
"This should never happen!");
nsRefPtr<TelephonyCall> modifiedCall;
nsRefPtr<TelephonyCall> outgoingCall;
nsRefPtr<TelephonyCall> modifiedCall
= GetCallFromEverywhere(aCallIndex);
// Update calls array first then state of a call in mCalls.
// Try to use the outgoing call if we don't find the modified call.
if (!modifiedCall) {
nsRefPtr<TelephonyCall> outgoingCall = GetOutgoingCall();
if (aIsConference) {
// Add the call into mGroup if it hasn't been there, otherwise we simply
// update its call state. We don't fire the statechange event on a call in
// conference here. Instead, the event will be fired later in
// TelephonyCallGroup::ChangeState(). Thus the sequence of firing the
// statechange events is guaranteed: first on TelephonyCallGroup then on
// individual TelephonyCall objects.
// If the call state isn't incoming but we do have an outgoing call then
// we must be seeing a status update for our outgoing call.
if (outgoingCall &&
aCallState != nsITelephonyProvider::CALL_STATE_INCOMING) {
outgoingCall->UpdateCallIndex(aCallIndex);
outgoingCall->UpdateEmergency(aIsEmergency);
modifiedCall.swap(outgoingCall);
}
}
modifiedCall = mGroup->GetCall(aCallIndex);
if (modifiedCall) {
modifiedCall->ChangeStateInternal(aCallState, false);
return NS_OK;
if (modifiedCall) {
if (!aIsConference) {
UpdateActiveCall(modifiedCall, aIsActive);
}
// The call becomes a conference call. Remove it from Telephony::mCalls and
// add it to mGroup.
modifiedCall = GetCall(aCallIndex);
if (modifiedCall) {
modifiedCall->ChangeStateInternal(aCallState, false);
if (modifiedCall->CallState() != aCallState) {
// We don't fire the statechange event on a call in conference here.
// Instead, the event will be fired later in
// TelephonyCallGroup::ChangeState(). Thus the sequence of firing the
// statechange events is guaranteed: first on TelephonyCallGroup then on
// individual TelephonyCall objects.
bool fireEvent = !aIsConference;
modifiedCall->ChangeStateInternal(aCallState, fireEvent);
}
nsRefPtr<TelephonyCallGroup> group = modifiedCall->GetGroup();
if (!group && aIsConference) {
// Add to conference.
NS_ASSERTION(mCalls.Contains(modifiedCall), "Should in mCalls");
mGroup->AddCall(modifiedCall);
RemoveCall(modifiedCall);
return NS_OK;
}
// Didn't find this call in mCalls or mGroup. Create a new call.
nsRefPtr<TelephonyCall> call =
TelephonyCall::Create(this, aNumber, aCallState, aCallIndex,
aIsEmergency, aIsConference);
NS_ASSERTION(call, "This should never fail!");
return NS_OK;
}
// Not a conference call. Remove the call from mGroup if it has been there.
modifiedCall = mGroup->GetCall(aCallIndex);
if (modifiedCall) {
if (aCallState != nsITelephonyProvider::CALL_STATE_DISCONNECTED) {
if (modifiedCall->CallState() != aCallState) {
modifiedCall->ChangeState(aCallState);
}
} else if (group && !aIsConference) {
// Remove from conference.
NS_ASSERTION(mGroup->CallsArray().Contains(modifiedCall), "Should in mGroup");
mGroup->RemoveCall(modifiedCall);
AddCall(modifiedCall);
} else {
modifiedCall->ChangeState(aCallState);
}
return NS_OK;
}
// Update calls in mCalls.
for (uint32_t index = 0; index < mCalls.Length(); index++) {
nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
if (tempCall->CallIndex() == kOutgoingPlaceholderCallIndex) {
NS_ASSERTION(!outgoingCall, "More than one outgoing call not supported!");
NS_ASSERTION(tempCall->CallState() ==
nsITelephonyProvider::CALL_STATE_DIALING,
"Something really wrong here!");
// Stash this for later, we may need it if aCallIndex doesn't match one of
// our other calls.
outgoingCall = tempCall;
} else if (tempCall->CallIndex() == aCallIndex) {
// We already know about this call so just update its state.
modifiedCall = tempCall;
outgoingCall = nullptr;
break;
}
}
// If nothing matched above and the call state isn't incoming but we do have
// an outgoing call then we must be seeing a status update for our outgoing
// call.
if (!modifiedCall &&
aCallState != nsITelephonyProvider::CALL_STATE_INCOMING &&
outgoingCall) {
outgoingCall->UpdateCallIndex(aCallIndex);
outgoingCall->UpdateEmergency(aIsEmergency);
modifiedCall.swap(outgoingCall);
}
if (modifiedCall) {
// See if this should replace our current active call.
if (aIsActive) {
mActiveCall = modifiedCall;
} else if (mActiveCall && mActiveCall->CallIndex() == aCallIndex) {
mActiveCall = nullptr;
}
// Change state.
modifiedCall->ChangeState(aCallState);
return NS_OK;
}
// Didn't know anything about this call before now.
// Do nothing since we didn't know anything about it before now and it's
// ended already.
if (aCallState == nsITelephonyProvider::CALL_STATE_DISCONNECTED) {
// Do nothing since we didn't know anything about it before now and it's
// been ended already.
return NS_OK;
}
// Didn't find this call in mCalls or mGroup. Create a new call.
nsRefPtr<TelephonyCall> call =
TelephonyCall::Create(this, aNumber, aCallState, aCallIndex, aIsEmergency);
TelephonyCall::Create(this, aNumber, aCallState, aCallIndex,
aIsEmergency, aIsConference);
NS_ASSERTION(call, "This should never fail!");
NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
NS_ASSERTION(aIsConference ? mGroup->CallsArray().Contains(call) :
mCalls.Contains(call),
"Should have auto-added new call!");
if (aCallState == nsITelephonyProvider::CALL_STATE_INCOMING) {
nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("incoming"), call);
@ -596,13 +581,8 @@ Telephony::EnumerateCallState(uint32_t aCallIndex, uint16_t aCallState,
// However, it is likely to have call state changes, i.e. CallStateChanged()
// being called, before the enumeration result comes back. We'd make sure
// we don't somehow add duplicates due to the race condition.
call = aIsConference ? mGroup->GetCall(aCallIndex) : GetCall(aCallIndex);
call = GetCallFromEverywhere(aCallIndex);
if (call) {
// We have the call either in mCalls or in mGroup. Skip it.
return NS_OK;
}
if (MoveCall(aCallIndex, aIsConference)) {
return NS_OK;
}
@ -649,28 +629,22 @@ NS_IMETHODIMP
Telephony::NotifyError(int32_t aCallIndex,
const nsAString& aError)
{
nsRefPtr<TelephonyCall> callToNotify;
if (!mCalls.IsEmpty()) {
// The connection is not established yet. Get the latest dialing call object.
if (aCallIndex == -1) {
nsRefPtr<TelephonyCall>& lastCall = mCalls[mCalls.Length() - 1];
if (lastCall->CallIndex() == kOutgoingPlaceholderCallIndex) {
callToNotify = lastCall;
}
} else {
// The connection has been established. Get the failed call.
callToNotify = GetCall(aCallIndex);
}
if (mCalls.IsEmpty()) {
NS_ERROR("No existing call!");
return NS_ERROR_UNEXPECTED;
}
nsRefPtr<TelephonyCall> callToNotify;
callToNotify = (aCallIndex == -1) ? GetOutgoingCall()
: GetCall(aCallIndex);
if (!callToNotify) {
NS_ERROR("Don't call me with a bad call index!");
return NS_ERROR_UNEXPECTED;
}
if (mActiveCall && mActiveCall->CallIndex() == callToNotify->CallIndex()) {
mActiveCall = nullptr;
}
UpdateActiveCall(callToNotify, false);
// Set the call state to 'disconnected' and remove it from the calls list.
callToNotify->NotifyError(aError);

View File

@ -111,7 +111,7 @@ public:
{
NS_ASSERTION(!mCalls.Contains(aCall), "Already know about this one!");
mCalls.AppendElement(aCall);
UpdateActiveCall(aCall, true);
UpdateActiveCall(aCall, IsActiveState(aCall->CallState()));
NotifyCallsChanged(aCall);
}
@ -145,6 +145,18 @@ private:
void
Shutdown();
static bool
IsValidNumber(const nsAString& aNumber);
static bool
IsActiveState(uint16_t aCallState);
bool
HasDialingCall();
bool
MatchActiveCall(TelephonyCall* aCall);
already_AddRefed<TelephonyCall>
DialInternal(bool isEmergency,
const nsAString& aNumber,
@ -160,20 +172,22 @@ private:
NotifyCallsChanged(TelephonyCall* aCall);
nsresult
DispatchCallEvent(const nsAString& aType,
TelephonyCall* aCall);
DispatchCallEvent(const nsAString& aType, TelephonyCall* aCall);
void
EnqueueEnumerationAck();
void
UpdateActiveCall(TelephonyCall* aCall, bool aIsAdding);
UpdateActiveCall(TelephonyCall* aCall, bool aIsActive);
already_AddRefed<TelephonyCall>
GetCall(uint32_t aCallIndex);
bool
MoveCall(uint32_t aCallIndex, bool aIsConference);
already_AddRefed<TelephonyCall>
GetOutgoingCall();
already_AddRefed<TelephonyCall>
GetCallFromEverywhere(uint32_t aCallIndex);
};
} // namespace dom