mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-02 14:30:43 +00:00
Bug 717451 - 'Telephony: Keep telephony objects on multiple pages in sync'. r=sicking.
--HG-- extra : transplant_source : %15%BB%92%8E%A38A%80%9E%A40T%E5BCi%BE%ACK%F7
This commit is contained in:
parent
7de7de1cff
commit
10fe365fe0
@ -41,13 +41,16 @@
|
||||
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "SystemWorkerManager.h"
|
||||
|
||||
@ -61,6 +64,10 @@ using mozilla::Preferences;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef nsAutoTArray<Telephony*, 2> TelephonyList;
|
||||
|
||||
TelephonyList* gTelephonyList;
|
||||
|
||||
template <class T>
|
||||
inline nsresult
|
||||
nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
|
||||
@ -110,6 +117,16 @@ nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
Telephony::Telephony()
|
||||
: mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false)
|
||||
{
|
||||
if (!gTelephonyList) {
|
||||
gTelephonyList = new TelephonyList();
|
||||
}
|
||||
|
||||
gTelephonyList->AppendElement(this);
|
||||
}
|
||||
|
||||
Telephony::~Telephony()
|
||||
{
|
||||
if (mRIL && mRILTelephonyCallback) {
|
||||
@ -119,6 +136,17 @@ Telephony::~Telephony()
|
||||
if (mRooted) {
|
||||
NS_DROP_JS_OBJECTS(this, Telephony);
|
||||
}
|
||||
|
||||
NS_ASSERTION(gTelephonyList, "This should never be null!");
|
||||
NS_ASSERTION(gTelephonyList->Contains(this), "Should be in the list!");
|
||||
|
||||
if (gTelephonyList->Length() == 1) {
|
||||
delete gTelephonyList;
|
||||
gTelephonyList = nsnull;
|
||||
}
|
||||
else {
|
||||
gTelephonyList->RemoveElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
@ -150,14 +178,37 @@ Telephony::Create(nsPIDOMWindow* aOwner, nsIRadioInterfaceLayer* aRIL)
|
||||
return telephony.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Telephony::SwitchActiveCall(TelephonyCall* aCall)
|
||||
already_AddRefed<TelephonyCall>
|
||||
Telephony::CreateNewDialingCall(const nsAString& aNumber)
|
||||
{
|
||||
if (mActiveCall) {
|
||||
// Put the call on hold?
|
||||
NS_NOTYETIMPLEMENTED("Implement me!");
|
||||
}
|
||||
mActiveCall = aCall;
|
||||
nsRefPtr<TelephonyCall> call =
|
||||
TelephonyCall::Create(this, aNumber,
|
||||
nsIRadioInterfaceLayer::CALL_STATE_DIALING);
|
||||
NS_ASSERTION(call, "This should never fail!");
|
||||
|
||||
NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
|
||||
|
||||
return call.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Telephony::NoteDialedCallFromOtherInstance(const nsAString& aNumber)
|
||||
{
|
||||
// We don't need to hang on to this call object, it is held alive by mCalls.
|
||||
nsRefPtr<TelephonyCall> call = CreateNewDialingCall(aNumber);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Telephony::NotifyCallsChanged(TelephonyCall* aCall)
|
||||
{
|
||||
nsRefPtr<CallEvent> event = CallEvent::Create(aCall);
|
||||
NS_ASSERTION(event, "This should never fail!");
|
||||
|
||||
nsresult rv =
|
||||
event->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("callschanged"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Telephony)
|
||||
@ -166,6 +217,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Telephony,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(incoming)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(callschanged)
|
||||
for (PRUint32 index = 0; index < tmp->mCalls.Length(); index++) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCalls[i]");
|
||||
cb.NoteXPCOMChild(tmp->mCalls[index]->ToISupports());
|
||||
@ -180,6 +232,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Telephony,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(incoming)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(callschanged)
|
||||
tmp->mCalls.Clear();
|
||||
tmp->mActiveCall = nsnull;
|
||||
tmp->mCallsArray = nsnull;
|
||||
@ -216,11 +269,16 @@ Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult)
|
||||
nsresult rv = mRIL->Dial(aNumber);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRefPtr<TelephonyCall> call =
|
||||
TelephonyCall::Create(this, aNumber, nsIRadioInterfaceLayer::CALL_STATE_DIALING);
|
||||
NS_ASSERTION(call, "This should never fail!");
|
||||
nsRefPtr<TelephonyCall> call = CreateNewDialingCall(aNumber);
|
||||
|
||||
NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
|
||||
// Notify other telephony objects that we just dialed.
|
||||
for (PRUint32 index = 0; index < gTelephonyList->Length(); index++) {
|
||||
Telephony*& telephony = gTelephonyList->ElementAt(index);
|
||||
if (telephony != this) {
|
||||
nsRefPtr<Telephony> kungFuDeathGrip = telephony;
|
||||
telephony->NoteDialedCallFromOtherInstance(aNumber);
|
||||
}
|
||||
}
|
||||
|
||||
call.forget(aResult);
|
||||
return NS_OK;
|
||||
@ -279,32 +337,6 @@ Telephony::GetActive(jsval* aActive)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Telephony::SetActive(const jsval& aActive)
|
||||
{
|
||||
if (aActive.isObject()) {
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
NS_ASSERTION(xpc, "This should never be null!");
|
||||
|
||||
nsISupports* native =
|
||||
xpc->GetNativeOfWrapper(mScriptContext->GetNativeContext(),
|
||||
&aActive.toObject());
|
||||
|
||||
nsCOMPtr<nsIDOMTelephonyCall> call = do_QueryInterface(native);
|
||||
if (call) {
|
||||
// See if this call has the same telephony object. Otherwise we can't use
|
||||
// it.
|
||||
TelephonyCall* concreteCall = static_cast<TelephonyCall*>(call.get());
|
||||
if (this == concreteCall->mTelephony) {
|
||||
SwitchActiveCall(concreteCall);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Telephony::GetCalls(jsval* aCalls)
|
||||
{
|
||||
@ -354,15 +386,8 @@ Telephony::StopTone()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Telephony::SendTones(const nsAString& aTones, PRUint32 aToneDuration,
|
||||
PRUint32 aIntervalDuration)
|
||||
{
|
||||
NS_NOTYETIMPLEMENTED("Implement me!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(Telephony, incoming)
|
||||
NS_IMPL_EVENT_HANDLER(Telephony, callschanged)
|
||||
|
||||
NS_IMETHODIMP
|
||||
Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
|
||||
@ -378,7 +403,8 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
|
||||
nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
|
||||
if (tempCall->CallIndex() == kOutgoingPlaceholderCallIndex) {
|
||||
NS_ASSERTION(!outgoingCall, "More than one outgoing call not supported!");
|
||||
NS_ASSERTION(tempCall->CallState() == nsIRadioInterfaceLayer::CALL_STATE_DIALING,
|
||||
NS_ASSERTION(tempCall->CallState() ==
|
||||
nsIRadioInterfaceLayer::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.
|
||||
@ -407,7 +433,7 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
|
||||
|
||||
// See if this should replace our current active call.
|
||||
if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) {
|
||||
SwitchActiveCall(modifiedCall);
|
||||
mActiveCall = modifiedCall;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -486,22 +512,48 @@ NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony)
|
||||
// Do security checks. We assume that chrome is always allowed and we also
|
||||
// allow a single page specified by preferences.
|
||||
if (!nsContentUtils::IsSystemPrincipal(document->NodePrincipal())) {
|
||||
nsCOMPtr<nsIURI> documentURI;
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
nsresult rv =
|
||||
document->NodePrincipal()->GetURI(getter_AddRefs(documentURI));
|
||||
document->NodePrincipal()->GetURI(getter_AddRefs(originalURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString documentURL;
|
||||
rv = documentURI->GetSpec(documentURL);
|
||||
nsCOMPtr<nsIURI> documentURI;
|
||||
rv = originalURI->Clone(getter_AddRefs(documentURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Strip the query string (if there is one) before comparing.
|
||||
nsCOMPtr<nsIURL> documentURL = do_QueryInterface(documentURI);
|
||||
if (documentURL) {
|
||||
rv = documentURL->SetQuery(EmptyCString());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
bool allowed = false;
|
||||
|
||||
// The pref may not exist but in that case we deny access just as we do if
|
||||
// the url doesn't match.
|
||||
nsCString phoneAppURL;
|
||||
if (NS_FAILED(Preferences::GetCString(DOM_TELEPHONY_APP_PHONE_URL_PREF,
|
||||
&phoneAppURL)) ||
|
||||
!phoneAppURL.Equals(documentURL,
|
||||
nsCaseInsensitiveCStringComparator())) {
|
||||
nsCString whitelist;
|
||||
if (NS_SUCCEEDED(Preferences::GetCString(DOM_TELEPHONY_APP_PHONE_URL_PREF,
|
||||
&whitelist))) {
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService();
|
||||
NS_ENSURE_TRUE(ios, NS_ERROR_FAILURE);
|
||||
|
||||
nsCCharSeparatedTokenizer tokenizer(whitelist, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), tokenizer.nextToken(),
|
||||
nsnull, nsnull, ios))) {
|
||||
rv = documentURI->EqualsExceptRef(uri, &allowed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (allowed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowed) {
|
||||
*aTelephony = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ class Telephony : public nsDOMEventTargetHelper,
|
||||
nsCOMPtr<nsIRILTelephonyCallback> mRILTelephonyCallback;
|
||||
|
||||
NS_DECL_EVENT_HANDLER(incoming)
|
||||
NS_DECL_EVENT_HANDLER(callschanged)
|
||||
|
||||
TelephonyCall* mActiveCall;
|
||||
nsTArray<nsRefPtr<TelephonyCall> > mCalls;
|
||||
@ -99,6 +100,7 @@ public:
|
||||
NS_ASSERTION(!mCalls.Contains(aCall), "Already know about this one!");
|
||||
mCalls.AppendElement(aCall);
|
||||
mCallsArray = nsnull;
|
||||
NotifyCallsChanged(aCall);
|
||||
}
|
||||
|
||||
void
|
||||
@ -107,6 +109,7 @@ public:
|
||||
NS_ASSERTION(mCalls.Contains(aCall), "Didn't know about this one!");
|
||||
mCalls.RemoveElement(aCall);
|
||||
mCallsArray = nsnull;
|
||||
NotifyCallsChanged(aCall);
|
||||
}
|
||||
|
||||
nsIRadioInterfaceLayer*
|
||||
@ -128,14 +131,17 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
Telephony()
|
||||
: mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false)
|
||||
{ }
|
||||
|
||||
Telephony();
|
||||
~Telephony();
|
||||
|
||||
already_AddRefed<TelephonyCall>
|
||||
CreateNewDialingCall(const nsAString& aNumber);
|
||||
|
||||
void
|
||||
SwitchActiveCall(TelephonyCall* aCall);
|
||||
NoteDialedCallFromOtherInstance(const nsAString& aNumber);
|
||||
|
||||
nsresult
|
||||
NotifyCallsChanged(TelephonyCall* aCall);
|
||||
|
||||
class RILTelephonyCallback : public nsIRILTelephonyCallback
|
||||
{
|
||||
|
@ -43,7 +43,7 @@
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMTelephonyCall;
|
||||
|
||||
[scriptable, builtinclass, uuid(047be0d8-a9cd-49aa-8948-2f60ff3a7a18)]
|
||||
[scriptable, builtinclass, uuid(0de46b73-be83-4970-ad15-45f92cb0902a)]
|
||||
interface nsIDOMTelephony : nsIDOMEventTarget
|
||||
{
|
||||
nsIDOMTelephonyCall dial(in DOMString number);
|
||||
@ -53,16 +53,14 @@ interface nsIDOMTelephony : nsIDOMEventTarget
|
||||
|
||||
// The call that is "active", i.e. receives microphone input and tones
|
||||
// generated via startTone.
|
||||
attribute jsval active;
|
||||
readonly attribute jsval active;
|
||||
|
||||
// Array of all calls that are currently connected.
|
||||
readonly attribute jsval calls;
|
||||
|
||||
void startTone(in DOMString tone);
|
||||
void stopTone();
|
||||
void sendTones(in DOMString tones,
|
||||
[optional] in unsigned long toneDuration,
|
||||
[optional] in unsigned long intervalDuration);
|
||||
|
||||
attribute nsIDOMEventListener onincoming;
|
||||
attribute nsIDOMEventListener oncallschanged;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user