Bug 674726 - WebTelephony. r=philikon+mounir, sr=sicking. Not part of the default build.

--HG--
extra : transplant_source : %1A%23%10d%88%B3%DA%87%C9%DD0%E6P%1Ct%AD%7D%80%B6%B4
This commit is contained in:
Ben Turner 2012-01-09 14:28:47 -08:00
Родитель 03ac2b686a
Коммит 288be4f200
28 изменённых файлов: 1936 добавлений и 676 удалений

Просмотреть файл

@ -46,6 +46,9 @@ pref("browser.homescreenURL", "file:///system/home/homescreen.html");
pref("browser.homescreenURL", "file:///data/local/homescreen.html,file:///system/home/homescreen.html");
#endif
// URL for the dialer application.
pref("dom.telephony.app.phone.url", "http://localhost:7777/dialer/dialer.html");
// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
pref("browser.viewport.scaleRatio", -1);

Просмотреть файл

@ -83,12 +83,12 @@ DIRS += \
workers \
$(NULL)
ifdef MOZ_B2G_RIL #{
ifdef MOZ_B2G_RIL
DIRS += \
telephony \
wifi \
$(NULL)
endif #}
endif
ifdef ENABLE_TESTS
DIRS += tests

Просмотреть файл

@ -137,6 +137,10 @@ ifdef MOZ_JSDEBUGGER
DEFINES += -DMOZ_JSDEBUGGER
endif
ifdef MOZ_B2G_RIL
DEFINES += -DMOZ_B2G_RIL
endif
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk

Просмотреть файл

@ -75,6 +75,10 @@
#include "nsIWebNavigation.h"
#include "mozilla/ClearOnShutdown.h"
#ifdef MOZ_B2G_RIL
#include "TelephonyFactory.h"
#endif
// This should not be in the namespace.
DOMCI_DATA(Navigator, mozilla::dom::Navigator)
@ -123,6 +127,9 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorBattery)
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorDesktopNotification)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorSms)
#ifdef MOZ_B2G_RIL
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorTelephony)
#endif
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
NS_INTERFACE_MAP_END
@ -159,6 +166,12 @@ Navigator::Invalidate()
mSmsManager->Shutdown();
mSmsManager = nsnull;
}
#ifdef MOZ_B2G_RIL
if (mTelephony) {
mTelephony = nsnull;
}
#endif
}
nsPIDOMWindow *
@ -1018,6 +1031,34 @@ Navigator::GetMozSms(nsIDOMMozSmsManager** aSmsManager)
return NS_OK;
}
#ifdef MOZ_B2G_RIL
//*****************************************************************************
// nsNavigator::nsIDOMNavigatorTelephony
//*****************************************************************************
NS_IMETHODIMP
Navigator::GetMozTelephony(nsIDOMTelephony** aTelephony)
{
nsCOMPtr<nsIDOMTelephony> telephony = mTelephony;
if (!telephony) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsresult rv = NS_NewTelephony(window, getter_AddRefs(mTelephony));
NS_ENSURE_SUCCESS(rv, rv);
// mTelephony may be null here!
telephony = mTelephony;
}
telephony.forget(aTelephony);
return NS_OK;
}
#endif // MOZ_B2G_RIL
PRInt64
Navigator::SizeOf() const
{

Просмотреть файл

@ -58,6 +58,11 @@ class nsGeolocation;
class nsDesktopNotificationCenter;
class nsPIDOMWindow;
#ifdef MOZ_B2G_RIL
#include "nsIDOMNavigatorTelephony.h"
class nsIDOMTelephony;
#endif
//*****************************************************************************
// Navigator: Script "navigator" object
//*****************************************************************************
@ -79,6 +84,9 @@ class Navigator : public nsIDOMNavigator,
public nsIDOMNavigatorDesktopNotification,
public nsIDOMMozNavigatorBattery,
public nsIDOMMozNavigatorSms
#ifdef MOZ_B2G_RIL
, public nsIDOMNavigatorTelephony
#endif
{
public:
Navigator(nsPIDOMWindow *aInnerWindow);
@ -92,6 +100,10 @@ public:
NS_DECL_NSIDOMMOZNAVIGATORBATTERY
NS_DECL_NSIDOMMOZNAVIGATORSMS
#ifdef MOZ_B2G_RIL
NS_DECL_NSIDOMNAVIGATORTELEPHONY
#endif
static void Init();
void Invalidate();
@ -118,6 +130,9 @@ private:
nsRefPtr<nsDesktopNotificationCenter> mNotification;
nsRefPtr<battery::BatteryManager> mBatteryManager;
nsRefPtr<sms::SmsManager> mSmsManager;
#ifdef MOZ_B2G_RIL
nsCOMPtr<nsIDOMTelephony> mTelephony;
#endif
nsWeakPtr mWindow;
};

Просмотреть файл

@ -516,6 +516,12 @@
#include "nsIDOMSmsEvent.h"
#include "nsIPrivateDOMEvent.h"
#ifdef MOZ_B2G_RIL
#include "Telephony.h"
#include "TelephonyCall.h"
#include "CallEvent.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
@ -1553,6 +1559,15 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CustomEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#ifdef MOZ_B2G_RIL
NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(TelephonyCall, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif
};
// Objects that should be constructable through |new Name();|
@ -2341,6 +2356,9 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorBattery,
battery::BatteryManager::HasSupport())
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozNavigatorSms)
#ifdef MOZ_B2G_RIL
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorTelephony)
#endif
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin)
@ -4245,6 +4263,23 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
#ifdef MOZ_B2G_RIL
DOM_CLASSINFO_MAP_BEGIN(Telephony, nsIDOMTelephony)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMTelephony)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(TelephonyCall, nsIDOMTelephonyCall)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMTelephonyCall)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CallEvent, nsIDOMCallEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCallEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
DOM_CLASSINFO_MAP_END
#endif
#ifdef NS_DEBUG
{
PRUint32 i = ArrayLength(sClassInfoData);

Просмотреть файл

@ -526,3 +526,9 @@ DOMCI_CLASS(MozCSSKeyframesRule)
DOMCI_CLASS(MediaQueryList)
DOMCI_CLASS(CustomEvent)
#ifdef MOZ_B2G_RIL
DOMCI_CLASS(Telephony)
DOMCI_CLASS(TelephonyCall)
DOMCI_CLASS(CallEvent)
#endif

Просмотреть файл

@ -56,8 +56,10 @@
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
#else
#elif defined(__GNUC__)
#define LOG(args...) printf(args);
#else
#define LOG(args) printf args
#endif
USING_WORKERS_NAMESPACE
@ -150,7 +152,8 @@ ConnectWorkerToRIL::RunTask(JSContext *aCx)
NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?");
JSObject *workerGlobal = JS_GetGlobalObject(aCx);
return JS_DefineFunction(aCx, workerGlobal, "postRILMessage", PostToRIL, 1, 0);
return !!JS_DefineFunction(aCx, workerGlobal, "postRILMessage", PostToRIL, 1,
0);
}
class RILReceiver : public RilConsumer

Просмотреть файл

@ -0,0 +1,91 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "CallEvent.h"
#include "nsDOMClassInfo.h"
#include "Telephony.h"
#include "TelephonyCall.h"
USING_TELEPHONY_NAMESPACE
// static
already_AddRefed<CallEvent>
CallEvent::Create(TelephonyCall* aCall)
{
NS_ASSERTION(aCall, "Null pointer!");
nsRefPtr<CallEvent> event = new CallEvent();
event->mCall = aCall;
return event.forget();
}
NS_IMPL_CYCLE_COLLECTION_CLASS(CallEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CallEvent,
nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mCall->ToISupports(),
TelephonyCall, "mCall")
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CallEvent,
nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCall)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CallEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMCallEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CallEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(CallEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(CallEvent, nsDOMEvent)
DOMCI_DATA(CallEvent, CallEvent)
NS_IMETHODIMP
CallEvent::GetCall(nsIDOMTelephonyCall** aCall)
{
nsCOMPtr<nsIDOMTelephonyCall> call = mCall;
call.forget(aCall);
return NS_OK;
}

99
dom/telephony/CallEvent.h Normal file
Просмотреть файл

@ -0,0 +1,99 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_telephony_callevent_h__
#define mozilla_dom_telephony_callevent_h__
#include "TelephonyCommon.h"
#include "nsIDOMCallEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsDOMEvent.h"
BEGIN_TELEPHONY_NAMESPACE
class CallEvent : public nsDOMEvent,
public nsIDOMCallEvent
{
nsRefPtr<TelephonyCall> mCall;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_NSIDOMCALLEVENT
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CallEvent, nsDOMEvent)
static already_AddRefed<CallEvent>
Create(TelephonyCall* aCall);
nsresult
Dispatch(nsIDOMEventTarget* aTarget, const nsAString& aEventType)
{
NS_ASSERTION(aTarget, "Null pointer!");
NS_ASSERTION(!aEventType.IsEmpty(), "Empty event type!");
nsresult rv = InitEvent(aEventType, false, false);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetTrusted(true);
NS_ENSURE_SUCCESS(rv, rv);
nsIDOMEvent* thisEvent =
static_cast<nsDOMEvent*>(const_cast<CallEvent*>(this));
bool dummy;
rv = aTarget->DispatchEvent(thisEvent, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
private:
CallEvent()
: nsDOMEvent(nsnull, nsnull)
{ }
~CallEvent()
{ }
};
END_TELEPHONY_NAMESPACE
#endif // mozilla_dom_telephony_callevent_h__

Просмотреть файл

@ -50,14 +50,21 @@ FORCE_STATIC_LIB = 1
include $(topsrcdir)/dom/dom-config.mk
CPPSRCS = \
Telephony.cpp \
TelephonyCall.cpp \
CallEvent.cpp \
$(NULL)
XPIDLSRCS = \
mozIDOMTelephony.idl \
nsIDOMNavigatorTelephony.idl \
nsIDOMTelephony.idl \
nsIDOMTelephonyCall.idl \
nsIDOMCallEvent.idl \
nsITelephone.idl \
$(NULL)
EXTRA_COMPONENTS = \
Telephony.manifest \
Telephony.js \
nsTelephonyWorker.manifest \
nsTelephonyWorker.js \
$(NULL)

465
dom/telephony/Telephony.cpp Normal file
Просмотреть файл

@ -0,0 +1,465 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "Telephony.h"
#include "nsIDocument.h"
#include "nsIURI.h"
#include "nsPIDOMWindow.h"
#include "jsapi.h"
#include "mozilla/Preferences.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsServiceManagerUtils.h"
#include "CallEvent.h"
#include "TelephonyCall.h"
USING_TELEPHONY_NAMESPACE
using mozilla::Preferences;
#define DOM_TELEPHONY_APP_PHONE_URL_PREF "dom.telephony.app.phone.url"
namespace {
template <class T>
inline nsresult
nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
const nsTArray<nsRefPtr<T> >& aSourceArray,
JSObject** aResultArray)
{
NS_ASSERTION(aCx, "Null context!");
NS_ASSERTION(aGlobal, "Null global!");
JSAutoRequest ar(aCx);
JSAutoEnterCompartment ac;
if (!ac.enter(aCx, aGlobal)) {
NS_WARNING("Failed to enter compartment!");
return NS_ERROR_FAILURE;
}
JSObject* arrayObj;
if (aSourceArray.IsEmpty()) {
arrayObj = JS_NewArrayObject(aCx, 0, nsnull);
} else {
nsTArray<jsval> valArray;
valArray.SetLength(aSourceArray.Length());
for (PRUint32 index = 0; index < valArray.Length(); index++) {
nsISupports* obj = aSourceArray[index]->ToISupports();
nsresult rv =
nsContentUtils::WrapNative(aCx, aGlobal, obj, &valArray[index]);
NS_ENSURE_SUCCESS(rv, rv);
}
arrayObj = JS_NewArrayObject(aCx, valArray.Length(), valArray.Elements());
}
if (!arrayObj) {
return NS_ERROR_OUT_OF_MEMORY;
}
// XXX This is not what Jonas wants. He wants it to be live.
if (!JS_FreezeObject(aCx, arrayObj)) {
return NS_ERROR_FAILURE;
}
*aResultArray = arrayObj;
return NS_OK;
}
} // anonymous namespace
Telephony::~Telephony()
{
if (mTelephone && mTelephoneCallback) {
mTelephone->UnregisterCallback(mTelephoneCallback);
}
if (mRooted) {
NS_DROP_JS_OBJECTS(this, Telephony);
}
}
// static
already_AddRefed<Telephony>
Telephony::Create(nsPIDOMWindow* aOwner, nsITelephone* aTelephone)
{
NS_ASSERTION(aOwner, "Null owner!");
NS_ASSERTION(aTelephone, "Null telephone!");
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
NS_ENSURE_TRUE(sgo, nsnull);
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
NS_ENSURE_TRUE(scriptContext, nsnull);
nsRefPtr<Telephony> telephony = new Telephony();
telephony->mOwner = aOwner;
telephony->mScriptContext.swap(scriptContext);
telephony->mTelephone = aTelephone;
telephony->mTelephoneCallback = new TelephoneCallback(telephony);
nsresult rv = aTelephone->EnumerateCalls(telephony->mTelephoneCallback);
NS_ENSURE_SUCCESS(rv, nsnull);
rv = aTelephone->RegisterCallback(telephony->mTelephoneCallback);
NS_ENSURE_SUCCESS(rv, nsnull);
return telephony.forget();
}
void
Telephony::SwitchActiveCall(TelephonyCall* aCall)
{
if (mActiveCall) {
// Put the call on hold?
NS_NOTYETIMPLEMENTED("Implement me!");
}
mActiveCall = aCall;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(Telephony)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Telephony,
nsDOMEventTargetWrapperCache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(incoming)
for (PRUint32 index = 0; index < tmp->mCalls.Length(); index++) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCalls[i]");
cb.NoteXPCOMChild(tmp->mCalls[index]->ToISupports());
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Telephony,
nsDOMEventTargetWrapperCache)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mCallsArray, "mCallsArray")
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Telephony,
nsDOMEventTargetWrapperCache)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(incoming)
tmp->mCalls.Clear();
tmp->mActiveCall = nsnull;
tmp->mCallsArray = nsnull;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Telephony)
NS_INTERFACE_MAP_ENTRY(nsIDOMTelephony)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Telephony)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
NS_IMPL_ADDREF_INHERITED(Telephony, nsDOMEventTargetWrapperCache)
NS_IMPL_RELEASE_INHERITED(Telephony, nsDOMEventTargetWrapperCache)
DOMCI_DATA(Telephony, Telephony)
NS_IMPL_ISUPPORTS1(Telephony::TelephoneCallback, nsITelephoneCallback)
NS_IMETHODIMP
Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult)
{
NS_ENSURE_ARG(!aNumber.IsEmpty());
nsresult rv = mTelephone->Dial(aNumber);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<TelephonyCall> call =
TelephonyCall::Create(this, aNumber, nsITelephone::CALL_STATE_DIALING);
NS_ASSERTION(call, "This should never fail!");
NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
call.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
Telephony::GetMuted(bool* aMuted)
{
nsresult rv = mTelephone->GetMicrophoneMuted(aMuted);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Telephony::SetMuted(bool aMuted)
{
nsresult rv = mTelephone->SetMicrophoneMuted(aMuted);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Telephony::GetSpeakerEnabled(bool* aSpeakerEnabled)
{
nsresult rv = mTelephone->GetSpeakerEnabled(aSpeakerEnabled);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Telephony::SetSpeakerEnabled(bool aSpeakerEnabled)
{
nsresult rv = mTelephone->SetSpeakerEnabled(aSpeakerEnabled);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Telephony::GetActive(jsval* aActive)
{
if (!mActiveCall) {
aActive->setNull();
return NS_OK;
}
nsresult rv =
nsContentUtils::WrapNative(mScriptContext->GetNativeContext(),
mScriptContext->GetNativeGlobal(),
mActiveCall->ToISupports(), aActive);
NS_ENSURE_SUCCESS(rv, rv);
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)
{
JSObject* calls = mCallsArray;
if (!calls) {
nsresult rv =
nsTArrayToJSArray(mScriptContext->GetNativeContext(),
mScriptContext->GetNativeGlobal(), mCalls, &calls);
NS_ENSURE_SUCCESS(rv, rv);
if (!mRooted) {
NS_HOLD_JS_OBJECTS(this, Telephony);
mRooted = true;
}
mCallsArray = calls;
}
aCalls->setObject(*calls);
return NS_OK;
}
NS_IMETHODIMP
Telephony::StartTone(const nsAString& aDTMFChar)
{
if (aDTMFChar.IsEmpty()) {
NS_WARNING("Empty tone string will be ignored");
return NS_OK;
}
if (aDTMFChar.Length() > 1) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv = mTelephone->StartTone(aDTMFChar);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Telephony::StopTone()
{
nsresult rv = mTelephone->StopTone();
NS_ENSURE_SUCCESS(rv, rv);
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_IMETHODIMP
Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
const nsAString& aNumber)
{
// If we already know about this call then just update its state.
for (PRUint32 index = 0; index < mCalls.Length(); index++) {
nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
if (tempCall->CallIndex() == aCallIndex) {
// This can call back and modify the array... Grab a real ref here.
nsRefPtr<TelephonyCall> call = tempCall;
// See if this should replace our current active call.
if (aCallState == nsITelephone::CALL_STATE_CONNECTED) {
SwitchActiveCall(call);
}
// Change state.
call->ChangeState(aCallState);
return NS_OK;
}
}
// Didn't know anything about this call before now, must be incoming.
NS_ASSERTION(aCallState == nsITelephone::CALL_STATE_INCOMING,
"Serious logic problem here!");
nsRefPtr<TelephonyCall> call =
TelephonyCall::Create(this, aNumber, aCallState, aCallIndex);
NS_ASSERTION(call, "This should never fail!");
NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
// Dispatch incoming event.
nsRefPtr<CallEvent> event = CallEvent::Create(call);
NS_ASSERTION(event, "This should never fail!");
nsresult rv =
event->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("incoming"));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Telephony::EnumerateCallState(PRUint32 aCallIndex, PRUint16 aCallState,
const nsAString& aNumber, bool aIsActive,
bool* aContinue)
{
#ifdef DEBUG
// Make sure we don't somehow add duplicates.
for (PRUint32 index = 0; index < mCalls.Length(); index++) {
NS_ASSERTION(mCalls[index]->CallIndex() != aCallIndex,
"Something is really wrong here!");
}
#endif
nsRefPtr<TelephonyCall> call =
TelephonyCall::Create(this, aNumber, aCallState, aCallIndex);
NS_ASSERTION(call, "This should never fail!");
NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
if (aIsActive) {
NS_ASSERTION(!mActiveCall, "Already have an active call!");
mActiveCall = call;
}
*aContinue = true;
return NS_OK;
}
nsresult
NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony)
{
NS_ASSERTION(aWindow, "Null pointer!");
// Make sure we're dealing with an inner window.
nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
aWindow :
aWindow->GetCurrentInnerWindow();
NS_ENSURE_TRUE(innerWindow, NS_ERROR_FAILURE);
if (!nsContentUtils::CanCallerAccess(innerWindow)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsCOMPtr<nsIDocument> document =
do_QueryInterface(innerWindow->GetExtantDocument());
NS_ENSURE_TRUE(document, NS_NOINTERFACE);
nsCOMPtr<nsIURI> documentURI;
nsresult rv = document->NodePrincipal()->GetURI(getter_AddRefs(documentURI));
NS_ENSURE_SUCCESS(rv, rv);
nsCString documentURL;
rv = documentURI->GetSpec(documentURL);
NS_ENSURE_SUCCESS(rv, rv);
nsCString phoneAppURL;
rv = Preferences::GetCString(DOM_TELEPHONY_APP_PHONE_URL_PREF, &phoneAppURL);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Telephony> telephony;
if (phoneAppURL.Equals(documentURL, nsCaseInsensitiveCStringComparator())) {
nsCOMPtr<nsITelephone> telephone =
do_GetService("@mozilla.org/telephony/radio-interface;1");
NS_ENSURE_TRUE(telephone, NS_ERROR_FAILURE);
telephony = Telephony::Create(innerWindow, telephone);
}
telephony.forget(aTelephony);
return NS_OK;
}

158
dom/telephony/Telephony.h Normal file
Просмотреть файл

@ -0,0 +1,158 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_telephony_telephony_h__
#define mozilla_dom_telephony_telephony_h__
#include "TelephonyCommon.h"
#include "nsIDOMTelephony.h"
#include "nsIDOMTelephonyCall.h"
#include "nsITelephone.h"
class nsIScriptContext;
class nsPIDOMWindow;
BEGIN_TELEPHONY_NAMESPACE
class Telephony : public nsDOMEventTargetWrapperCache,
public nsIDOMTelephony
{
nsCOMPtr<nsITelephone> mTelephone;
nsCOMPtr<nsITelephoneCallback> mTelephoneCallback;
NS_DECL_EVENT_HANDLER(incoming);
TelephonyCall* mActiveCall;
nsTArray<nsRefPtr<TelephonyCall> > mCalls;
// Cached calls array object. Cleared whenever mCalls changes and then rebuilt
// once a page looks for the liveCalls attribute.
JSObject* mCallsArray;
bool mRooted;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMTELEPHONY
NS_DECL_NSITELEPHONECALLBACK
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
Telephony,
nsDOMEventTargetWrapperCache)
static already_AddRefed<Telephony>
Create(nsPIDOMWindow* aOwner, nsITelephone* aTelephone);
nsIDOMEventTarget*
ToIDOMEventTarget() const
{
return static_cast<nsDOMEventTargetWrapperCache*>(
const_cast<Telephony*>(this));
}
nsISupports*
ToISupports() const
{
return ToIDOMEventTarget();
}
void
AddCall(TelephonyCall* aCall)
{
NS_ASSERTION(!mCalls.Contains(aCall), "Already know about this one!");
mCalls.AppendElement(aCall);
mCallsArray = nsnull;
}
void
RemoveCall(TelephonyCall* aCall)
{
NS_ASSERTION(mCalls.Contains(aCall), "Didn't know about this one!");
mCalls.RemoveElement(aCall);
mCallsArray = nsnull;
}
nsITelephone*
Telephone() const
{
return mTelephone;
}
nsPIDOMWindow*
Owner() const
{
return mOwner;
}
nsIScriptContext*
ScriptContext() const
{
return mScriptContext;
}
private:
Telephony()
: mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false)
{ }
~Telephony();
void
SwitchActiveCall(TelephonyCall* aCall);
class TelephoneCallback : public nsITelephoneCallback
{
Telephony* mTelephony;
public:
NS_DECL_ISUPPORTS
NS_FORWARD_NSITELEPHONECALLBACK(mTelephony->)
TelephoneCallback(Telephony* aTelephony)
: mTelephony(aTelephony)
{
NS_ASSERTION(mTelephony, "Null pointer!");
}
};
};
END_TELEPHONY_NAMESPACE
#endif // mozilla_dom_telephony_telephony_h__

Просмотреть файл

@ -1,448 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Philipp von Weitershausen <philipp@weitershausen.de>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const TELEPHONY_CID = Components.ID("{37e248d2-02ff-469b-bb31-eef5a4a4bee3}");
const TELEPHONY_CONTRACTID = "@mozilla.org/telephony;1";
const TELEPHONY_CALL_CID = Components.ID("{6b9b3daf-e5ea-460b-89a5-641ee20dd577}");
const TELEPHONY_CALL_CONTRACTID = "@mozilla.org/telephony-call;1";
const DOM_RADIOSTATE_UNAVAILABLE = "unavailable";
const DOM_RADIOSTATE_OFF = "off";
const DOM_RADIOSTATE_READY = "ready";
const DOM_CARDSTATE_UNAVAILABLE = "unavailable";
const DOM_CARDSTATE_ABSENT = "absent";
const DOM_CARDSTATE_PIN_REQUIRED = "pin_required";
const DOM_CARDSTATE_PUK_REQUIRED = "puk_required";
const DOM_CARDSTATE_NETWORK_LOCKED = "network_locked";
const DOM_CARDSTATE_NOT_READY = "not_ready";
const DOM_CARDSTATE_READY = "ready";
const DOM_CALL_READYSTATE_DIALING = "dialing";
const DOM_CALL_READYSTATE_RINGING = "ringing";
const DOM_CALL_READYSTATE_BUSY = "busy";
const DOM_CALL_READYSTATE_CONNECTING = "connecting";
const DOM_CALL_READYSTATE_CONNECTED = "connected";
const DOM_CALL_READYSTATE_DISCONNECTING = "disconnecting";
const DOM_CALL_READYSTATE_DISCONNECTED = "disconnected";
const DOM_CALL_READYSTATE_INCOMING = "incoming";
const DOM_CALL_READYSTATE_HOLDING = "holding";
const DOM_CALL_READYSTATE_HELD = "held";
const CALLINDEX_TEMPORARY_DIALING = -1;
/**
* Define an event listener slot on an object, e.g.
*
* obj.onerror = function () {...}
*
* will register the function as an event handler for the "error" event
* if the "error" slot was defined on 'obj' or its prototype.
*/
function defineEventListenerSlot(object, event_type) {
let property_name = "on" + event_type;
let hidden_name = "_on" + event_type;
let bound_name = "_bound_on" + event_type;
object.__defineGetter__(property_name, function getter() {
return this[hidden_name];
});
object.__defineSetter__(property_name, function setter(handler) {
let old_handler = this[bound_name];
if (old_handler) {
this.removeEventListener(event_type, old_handler);
}
// Bind the handler to the object so that its 'this' is correct.
let bound_handler = handler.bind(this);
this.addEventListener(event_type, bound_handler);
this[hidden_name] = handler;
this[bound_name] = bound_handler;
});
}
/**
* Base object for event targets.
*/
function EventTarget() {}
EventTarget.prototype = {
addEventListener: function addEventListener(type, handler) {
//TODO verify that handler is an nsIDOMEventListener (or function)
if (!this._listeners) {
this._listeners = {};
}
if (!this._listeners[type]) {
this._listeners[type] = [];
}
if (this._listeners[type].indexOf(handler) != -1) {
// The handler is already registered. Ignore.
return;
}
this._listeners[type].push(handler);
},
removeEventListener: function removeEventListener(type, handler) {
let list, index;
if (this._listeners &&
(list = this._listeners[type]) &&
(index = list.indexOf(handler) != -1)) {
list.splice(index, 1);
return;
}
},
dispatchEvent: function dispatchEvent(event) {
//TODO this does not deal with bubbling, defaultPrevented, canceling, etc.
//TODO disallow re-dispatch of the same event if it's already being
// dispatched (recursion).
if (!this._listeners) {
return;
}
let handlerList = this._listeners[event.type];
if (!handlerList) {
return;
}
event.target = this;
// We need to worry about event handler mutations during the event firing.
// The correct behaviour is to *not* call any listeners that are added
// during the firing and to *not* call any listeners that are removed
// during the firing. To address this, we make a copy of the listener list
// before dispatching and then double-check that each handler is still
// registered before firing it.
let handlers = handlerList.slice();
handlers.forEach(function (handler) {
if (handlerList.indexOf(handler) == -1) {
return;
}
switch (typeof handler) {
case "function":
handler(event);
break;
case "object":
handler.handleEvent(event);
break;
}
});
}
};
/**
* Callback object that Telephony registers with nsITelephone.
* Telephony can't use itself because that might overload event handler
* attributes ('onfoobar').
*/
function TelephoneCallback(telephony) {
this.telephony = telephony;
}
TelephoneCallback.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephoneCallback]),
// nsITelephoneCallback
onsignalstrengthchange: function onsignalstrengthchange(event) {
this.telephony.signalStrength = event.signalStrength;
this.telephony._dispatchEventByType("signalstrengthchange");
},
onoperatorchange: function onoperatorchange(event) {
this.telephony.operator = event.operator;
this.telephony._dispatchEventByType("operatorchange");
},
onradiostatechange: function onradiostatechange(event) {
this.telephony.radioState = event.radioState;
this.telephony._dispatchEventByType("radiostatechange");
},
oncardstatechange: function oncardstatechange(event) {
this.telephony.cardState = event.cardState;
this.telephony._dispatchEventByType("cardstatechange");
},
oncallstatechange: function oncallstatechange(event) {
this.telephony._processCallState(event);
},
};
/**
* The navigator.mozTelephony object.
*/
function Telephony() {}
Telephony.prototype = {
__proto__: EventTarget.prototype,
classID: TELEPHONY_CID,
classInfo: XPCOMUtils.generateCI({classID: TELEPHONY_CID,
contractID: TELEPHONY_CONTRACTID,
interfaces: [Ci.mozIDOMTelephony,
Ci.nsIDOMEventTarget],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Telephony"}),
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMTelephony,
Ci.nsIDOMEventTarget,
Ci.nsIDOMGlobalPropertyInitializer]),
// nsIDOMGlobalPropertyInitializer
init: function init(window) {
this.window = window;
this.telephone = Cc["@mozilla.org/telephony/radio-interface;1"]
.createInstance(Ci.nsITelephone);
this.telephoneCallback = new TelephoneCallback(this);
//TODO switch to method suggested by bz in bug 707507
window.addEventListener("unload", function onunload(event) {
this.telephone.unregisterCallback(this.telephoneCallback);
this.telephoneCallback = null;
this.window = null;
}.bind(this));
this.telephone.registerCallback(this.telephoneCallback);
this.callsByIndex = {};
this.liveCalls = [];
// Populate existing state.
let currentState = this.telephone.currentState;
let states = currentState.currentCalls;
for (let i = 0; i < states.length; i++) {
let state = states[i];
let call = new TelephonyCall(this.telephone, state.callIndex);
call.readyState = state.callState;
call.number = state.number;
this.liveCalls.push(call);
this.callsByIndex[state.callIndex] = call;
}
this.operator = currentState.operator;
this.radioState = currentState.radioState;
this.cardState = currentState.cardState;
this.signalStrength = currentState.signalStrength;
},
_dispatchEventByType: function _dispatchEventByType(type) {
let event = this.window.document.createEvent("Event");
event.initEvent(type, false, false);
//event.isTrusted = true;
this.dispatchEvent(event);
},
_dispatchCallEvent: function _dispatchCallEvent(call, type, target) {
let event = this.window.document.createEvent("Event");
event.initEvent(type, false, false);
event.call = call; //XXX this is probably not going to work
//event.isTrusted = true;
target = target || call;
target.dispatchEvent(event);
},
_processCallState: function _processCallState(state) {
// If the call is dialing, chances are good that we just kicked that off
// so there's a call object without a callIndex. Let's fix that.
if (state.callState == DOM_CALL_READYSTATE_DIALING) {
let call = this.callsByIndex[CALLINDEX_TEMPORARY_DIALING];
if (call) {
call.callIndex = state.callIndex;
delete this.callsByIndex[CALLINDEX_TEMPORARY_DIALING];
this.callsByIndex[call.callIndex] = call;
// Nothing else to do, since the initial call state will already be
// DOM_CALL_READYSTATE_DIALING, so there's no event to dispatch.
return;
}
}
// If there is an existing call object, update state and dispatch event
// on it.
let call = this.callsByIndex[state.callIndex];
if (call) {
if (call.readyState == state.callState) {
// No change in ready state, don't dispatch an event.
return;
}
if (state.readyState == DOM_CALL_READYSTATE_DISCONNECTED) {
let index = this.liveCalls.indexOf(call);
if (index != -1) {
this.liveCalls.splice(index, 1);
}
delete this.callsByIndex[call.callIndex];
}
call.readyState = state.callState;
this._dispatchCallEvent(call, "readystatechange");
this._dispatchCallEvent(call, state.callState);
return;
}
// There's no call object yet, so let's create a new one, except when
// the state notified means that the call is over.
if (state.readyState == DOM_CALL_READYSTATE_DISCONNECTED) {
return;
}
call = new TelephonyCall(this.telephone, state.callIndex);
call.number = state.number;
call.readyState = state.callState;
this.callsByIndex[state.callIndex] = call;
this.liveCalls.push(call);
let target;
if (call.readyState == DOM_CALL_READYSTATE_INCOMING) {
target = this;
} else {
target = call;
this._dispatchCallEvent(call, "readystatechange");
}
this._dispatchCallEvent(call, state.callState, target);
},
callsByIndex: null,
// mozIDOMTelephony
liveCalls: null,
dial: function dial(number) {
this.telephone.dial(number);
// We don't know ahead of time what callIndex the call is going to have
// so let's assign a temp value for now and sort it out on the first
// 'callstatechange' event.
//TODO ensure there isn't already an outgoing call
let callIndex = CALLINDEX_TEMPORARY_DIALING;
let call = new TelephonyCall(this.telephone, callIndex);
call.readyState = DOM_CALL_READYSTATE_DIALING;
call.number = number;
this.callsByIndex[callIndex] = call;
this.liveCalls.push(call);
return call;
},
startTone: function startTone(dtmfChar) {
this.telephone.startTone(dtmfChar);
},
stopTone: function stopTone() {
this.telephone.stopTone();
},
get muted() {
return this.telephone.microphoneMuted;
},
set muted(value) {
this.telephone.microphoneMuted = value;
},
get speakerOn() {
return this.telephone.speakerEnabled;
},
set speakerOn(value) {
this.telephone.speakerEnabled = value;
},
// Additional stuff that's useful.
signalStrength: null,
operator: null,
radioState: DOM_RADIOSTATE_UNAVAILABLE,
cardState: DOM_CARDSTATE_UNAVAILABLE,
};
defineEventListenerSlot(Telephony.prototype, DOM_CALL_READYSTATE_INCOMING);
//XXX philikon's additions
defineEventListenerSlot(Telephony.prototype, "radiostatechange");
defineEventListenerSlot(Telephony.prototype, "cardstatechange");
defineEventListenerSlot(Telephony.prototype, "signalstrengthchange");
defineEventListenerSlot(Telephony.prototype, "operatorchange");
function TelephonyCall(telephone, callIndex) {
this.telephone = telephone;
this.callIndex = callIndex;
}
TelephonyCall.prototype = {
__proto__: EventTarget.prototype,
classID: TELEPHONY_CALL_CID,
classInfo: XPCOMUtils.generateCI({classID: TELEPHONY_CALL_CID,
contractID: TELEPHONY_CALL_CONTRACTID,
interfaces: [Ci.mozIDOMTelephonyCall,
Ci.nsIDOMEventTarget],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "TelephonyCall"}),
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMTelephonyCall,
Ci.nsIDOMEventTarget]),
callIndex: null,
// mozIDOMTelephonyCall
number: null,
readyState: null,
answer: function answer() {
if (this.readyState != DOM_CALL_READYSTATE_INCOMING) {
throw "Can only answer an incoming call!";
}
this.telephone.answerCall();
},
disconnect: function disconnect() {
if (this.readyState == DOM_CALL_READYSTATE_INCOMING) {
this.telephone.rejectCall();
} else {
this.telephone.hangUp(this.callIndex);
}
},
};
defineEventListenerSlot(TelephonyCall.prototype, "readystatechange");
defineEventListenerSlot(TelephonyCall.prototype, DOM_CALL_READYSTATE_RINGING);
defineEventListenerSlot(TelephonyCall.prototype, DOM_CALL_READYSTATE_BUSY);
defineEventListenerSlot(TelephonyCall.prototype, DOM_CALL_READYSTATE_CONNECTING);
defineEventListenerSlot(TelephonyCall.prototype, DOM_CALL_READYSTATE_CONNECTED);
defineEventListenerSlot(TelephonyCall.prototype, DOM_CALL_READYSTATE_DISCONNECTING);
defineEventListenerSlot(TelephonyCall.prototype, DOM_CALL_READYSTATE_DISCONNECTED);
const NSGetFactory = XPCOMUtils.generateNSGetFactory([Telephony]);

Просмотреть файл

@ -1,4 +0,0 @@
# Telephony.js
component {37e248d2-02ff-469b-bb31-eef5a4a4bee3} Telephony.js
contract @mozilla.org/telephony;1 {37e248d2-02ff-469b-bb31-eef5a4a4bee3}
category JavaScript-navigator-property mozTelephony @mozilla.org/telephony;1

Просмотреть файл

@ -0,0 +1,245 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "TelephonyCall.h"
#include "nsDOMClassInfo.h"
#include "CallEvent.h"
#include "Telephony.h"
USING_TELEPHONY_NAMESPACE
// static
already_AddRefed<TelephonyCall>
TelephonyCall::Create(Telephony* aTelephony, const nsAString& aNumber,
PRUint16 aCallState, PRUint32 aCallIndex)
{
NS_ASSERTION(aTelephony, "Null pointer!");
NS_ASSERTION(!aNumber.IsEmpty(), "Empty number!");
NS_ASSERTION(aCallIndex >= 1, "Invalid call index!");
nsRefPtr<TelephonyCall> call = new TelephonyCall();
call->mOwner = aTelephony->Owner();
call->mScriptContext = aTelephony->ScriptContext();
call->mTelephony = aTelephony;
call->mNumber = aNumber;
call->mCallIndex = aCallIndex;
call->ChangeStateInternal(aCallState, false);
return call.forget();
}
void
TelephonyCall::ChangeStateInternal(PRUint16 aCallState, bool aFireEvents)
{
nsRefPtr<TelephonyCall> kungFuDeathGrip(this);
nsString stateString;
switch (aCallState) {
case nsITelephone::CALL_STATE_DIALING:
stateString.AssignLiteral("dialing");
break;
case nsITelephone::CALL_STATE_RINGING:
stateString.AssignLiteral("ringing");
break;
case nsITelephone::CALL_STATE_BUSY:
stateString.AssignLiteral("busy");
break;
case nsITelephone::CALL_STATE_CONNECTING:
stateString.AssignLiteral("connecting");
break;
case nsITelephone::CALL_STATE_CONNECTED:
stateString.AssignLiteral("connected");
break;
case nsITelephone::CALL_STATE_HOLDING:
stateString.AssignLiteral("holding");
break;
case nsITelephone::CALL_STATE_HELD:
stateString.AssignLiteral("held");
break;
case nsITelephone::CALL_STATE_RESUMING:
stateString.AssignLiteral("resuming");
break;
case nsITelephone::CALL_STATE_DISCONNECTING:
stateString.AssignLiteral("disconnecting");
break;
case nsITelephone::CALL_STATE_DISCONNECTED:
stateString.AssignLiteral("disconnected");
break;
case nsITelephone::CALL_STATE_INCOMING:
stateString.AssignLiteral("incoming");
break;
default:
NS_NOTREACHED("Unknown state!");
}
mState = stateString;
mCallState = aCallState;
if (aCallState == nsITelephone::CALL_STATE_DISCONNECTED) {
NS_ASSERTION(mLive, "Should be live!");
mTelephony->RemoveCall(this);
mLive = false;
} else if (!mLive) {
mTelephony->AddCall(this);
mLive = true;
}
if (aFireEvents) {
nsRefPtr<CallEvent> event = CallEvent::Create(this);
NS_ASSERTION(event, "This should never fail!");
if (NS_FAILED(event->Dispatch(ToIDOMEventTarget(),
NS_LITERAL_STRING("statechange")))) {
NS_WARNING("Failed to dispatch statechange event!");
}
// This can change if the statechange handler called back here... Need to
// figure out something smarter.
if (mCallState == aCallState) {
event = CallEvent::Create(this);
NS_ASSERTION(event, "This should never fail!");
if (NS_FAILED(event->Dispatch(ToIDOMEventTarget(), stateString))) {
NS_WARNING("Failed to dispatch specific event!");
}
}
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(TelephonyCall)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TelephonyCall,
nsDOMEventTargetWrapperCache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mTelephony->ToISupports(),
Telephony, "mTelephony")
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(statechange)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(dialing)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(ringing)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(busy)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connecting)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connected)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disconnecting)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disconnected)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(incoming)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TelephonyCall,
nsDOMEventTargetWrapperCache)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTelephony)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(statechange)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(dialing)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(ringing)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(busy)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connecting)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connected)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disconnecting)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disconnected)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(incoming)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TelephonyCall)
NS_INTERFACE_MAP_ENTRY(nsIDOMTelephonyCall)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TelephonyCall)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
NS_IMPL_ADDREF_INHERITED(TelephonyCall, nsDOMEventTargetWrapperCache)
NS_IMPL_RELEASE_INHERITED(TelephonyCall, nsDOMEventTargetWrapperCache)
DOMCI_DATA(TelephonyCall, TelephonyCall)
NS_IMETHODIMP
TelephonyCall::GetNumber(nsAString& aNumber)
{
aNumber.Assign(mNumber);
return NS_OK;
}
NS_IMETHODIMP
TelephonyCall::GetState(nsAString& aState)
{
aState.Assign(mState);
return NS_OK;
}
NS_IMETHODIMP
TelephonyCall::Answer()
{
if (mCallState != nsITelephone::CALL_STATE_INCOMING) {
NS_WARNING("Answer on non-incoming call ignored!");
return NS_OK;
}
nsresult rv = mTelephony->Telephone()->AnswerCall(mCallIndex);
NS_ENSURE_SUCCESS(rv, rv);
ChangeStateInternal(nsITelephone::CALL_STATE_CONNECTING, true);
return NS_OK;
}
NS_IMETHODIMP
TelephonyCall::HangUp()
{
if (mCallState == nsITelephone::CALL_STATE_DISCONNECTING ||
mCallState == nsITelephone::CALL_STATE_DISCONNECTED) {
NS_WARNING("HangUp on previously disconnected call ignored!");
return NS_OK;
}
nsresult rv = mCallState == nsITelephone::CALL_STATE_INCOMING ?
mTelephony->Telephone()->RejectCall(mCallIndex) :
mTelephony->Telephone()->HangUp(mCallIndex);
NS_ENSURE_SUCCESS(rv, rv);
ChangeStateInternal(nsITelephone::CALL_STATE_DISCONNECTING, true);
return NS_OK;
}
NS_IMPL_EVENT_HANDLER(TelephonyCall, statechange)
NS_IMPL_EVENT_HANDLER(TelephonyCall, dialing)
NS_IMPL_EVENT_HANDLER(TelephonyCall, ringing)
NS_IMPL_EVENT_HANDLER(TelephonyCall, busy)
NS_IMPL_EVENT_HANDLER(TelephonyCall, connecting)
NS_IMPL_EVENT_HANDLER(TelephonyCall, connected)
NS_IMPL_EVENT_HANDLER(TelephonyCall, disconnecting)
NS_IMPL_EVENT_HANDLER(TelephonyCall, disconnected)
NS_IMPL_EVENT_HANDLER(TelephonyCall, incoming)

Просмотреть файл

@ -0,0 +1,131 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_telephony_telephonycall_h__
#define mozilla_dom_telephony_telephonycall_h__
#include "TelephonyCommon.h"
#include "nsIDOMTelephonyCall.h"
#include "nsITelephone.h"
class nsPIDOMWindow;
BEGIN_TELEPHONY_NAMESPACE
class TelephonyCall : public nsDOMEventTargetWrapperCache,
public nsIDOMTelephonyCall
{
NS_DECL_EVENT_HANDLER(statechange);
NS_DECL_EVENT_HANDLER(dialing);
NS_DECL_EVENT_HANDLER(ringing);
NS_DECL_EVENT_HANDLER(busy);
NS_DECL_EVENT_HANDLER(connecting);
NS_DECL_EVENT_HANDLER(connected);
NS_DECL_EVENT_HANDLER(disconnecting);
NS_DECL_EVENT_HANDLER(disconnected);
NS_DECL_EVENT_HANDLER(incoming);
nsRefPtr<Telephony> mTelephony;
nsString mNumber;
nsString mState;
PRUint32 mCallIndex;
PRUint16 mCallState;
bool mLive;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMTELEPHONYCALL
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TelephonyCall,
nsDOMEventTargetWrapperCache)
static already_AddRefed<TelephonyCall>
Create(Telephony* aTelephony, const nsAString& aNumber, PRUint16 aCallState,
PRUint32 aCallIndex = PR_UINT32_MAX);
nsIDOMEventTarget*
ToIDOMEventTarget() const
{
return static_cast<nsDOMEventTargetWrapperCache*>(
const_cast<TelephonyCall*>(this));
}
nsISupports*
ToISupports() const
{
return ToIDOMEventTarget();
}
void
ChangeState(PRUint16 aCallState)
{
ChangeStateInternal(aCallState, true);
}
PRUint32
CallIndex() const
{
return mCallIndex;
}
PRUint16
CallState() const
{
return mCallState;
}
private:
TelephonyCall()
: mCallIndex(PR_UINT32_MAX), mCallState(nsITelephone::CALL_STATE_UNKNOWN),
mLive(false)
{ }
~TelephonyCall()
{ }
void
ChangeStateInternal(PRUint16 aCallState, bool aFireEvents);
};
END_TELEPHONY_NAMESPACE
#endif // mozilla_dom_telephony_telephonycall_h__

Просмотреть файл

@ -0,0 +1,68 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_telephony_telephonycommon_h__
#define mozilla_dom_telephony_telephonycommon_h__
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDebug.h"
#include "nsDOMEventTargetWrapperCache.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#define BEGIN_TELEPHONY_NAMESPACE \
namespace mozilla { namespace dom { namespace telephony {
#define END_TELEPHONY_NAMESPACE \
} /* namespace telephony */ } /* namespace dom */ } /* namespace mozilla */
#define USING_TELEPHONY_NAMESPACE \
using namespace mozilla::dom::telephony;
class nsIDOMTelephony;
class nsIDOMTelephonyCall;
BEGIN_TELEPHONY_NAMESPACE
class Telephony;
class TelephonyCall;
END_TELEPHONY_NAMESPACE
#endif // mozilla_dom_telephony_telephonycommon_h__

Просмотреть файл

@ -0,0 +1,51 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_telephony_telephonyfactory_h__
#define mozilla_dom_telephony_telephonyfactory_h__
#include "nsIDOMTelephony.h"
#include "nsPIDOMWindow.h"
// Implemented in Telephony.cpp.
nsresult
NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony);
#endif // mozilla_dom_telephony_telephonyfactory_h__

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMEvent.idl"
interface nsIDOMTelephonyCall;
[scriptable, builtinclass, uuid(95625a90-7f1c-493b-b4bd-73f05834c6dd)]
interface nsIDOMCallEvent : nsIDOMEvent
{
readonly attribute nsIDOMTelephonyCall call;
};

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIDOMTelephony;
[scriptable, builtinclass, uuid(fb2f5927-41ea-442a-8292-81074f69dc41)]
interface nsIDOMNavigatorTelephony : nsISupports
{
readonly attribute nsIDOMTelephony mozTelephony;
};

Просмотреть файл

@ -0,0 +1,68 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
* Philipp von Weitershausen <philipp@weitershausen.de>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMEventTarget.idl"
interface nsIDOMEventListener;
interface nsIDOMTelephonyCall;
[scriptable, builtinclass, uuid(047be0d8-a9cd-49aa-8948-2f60ff3a7a18)]
interface nsIDOMTelephony : nsIDOMEventTarget
{
nsIDOMTelephonyCall dial(in DOMString number);
attribute boolean muted;
attribute boolean speakerEnabled;
// The call that is "active", i.e. receives microphone input and tones
// generated via startTone.
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;
};

Просмотреть файл

@ -1,3 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -14,12 +16,12 @@
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Philipp von Weitershausen <philipp@weitershausen.de>
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -36,52 +38,27 @@
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMEventTarget.idl"
#include "nsIDOMEvent.idl"
interface nsIDOMEventListener;
interface mozIDOMTelephonyCall;
[scriptable, uuid(c7b0046b-ee80-447c-8a95-a389003891bc)]
interface mozIDOMTelephony : nsIDOMEventTarget {
readonly attribute jsval liveCalls;
mozIDOMTelephonyCall dial(in DOMString number);
void startTone(in DOMString dtmfChar);
void stopTone();
attribute nsIDOMEventListener onincoming;
attribute boolean muted;
attribute boolean speakerOn;
//XXX philikon's additions
attribute nsIDOMEventListener onoperatorchange;
attribute nsIDOMEventListener onradiostatechange;
attribute nsIDOMEventListener oncardstatechange;
attribute nsIDOMEventListener onsignalstrengthchange;
readonly attribute jsval signalStrength;
readonly attribute jsval operator;
readonly attribute jsval radioState;
readonly attribute jsval cardState;
};
[scriptable, uuid(3d0060db-72ef-4b87-aceb-a16ed4c5253e)]
interface mozIDOMTelephonyCall : nsIDOMEventTarget {
[scriptable, builtinclass, uuid(832b7551-ff53-403f-9e2c-d7d28e2bb40b)]
interface nsIDOMTelephonyCall : nsIDOMEventTarget
{
readonly attribute DOMString number;
readonly attribute DOMString readyState;
readonly attribute DOMString state;
void answer();
void disconnect();
void hangUp();
attribute nsIDOMEventListener onreadystatechange;
attribute nsIDOMEventListener onstatechange;
attribute nsIDOMEventListener ondialing;
attribute nsIDOMEventListener onringing;
attribute nsIDOMEventListener onbusy;
attribute nsIDOMEventListener onconnecting;
attribute nsIDOMEventListener onconnected;
attribute nsIDOMEventListener ondisconnecting;
attribute nsIDOMEventListener ondisconnected;
};
[scriptable, uuid(c8c42b0c-a0dd-4702-9425-a7a80b2075c3)]
interface mozIDOMTelephonyCallEvent : nsIDOMEvent {
readonly attribute mozIDOMTelephonyCall call;
attribute nsIDOMEventListener onincoming;
};

Просмотреть файл

@ -40,31 +40,58 @@
[scriptable, uuid(9b7e3a01-9c45-4af3-81bb-1bf08a842226)]
interface nsITelephoneCallback : nsISupports
{
void oncallstatechange(in jsval event);
// 'callState' uses the CALL_STATE values from nsITelephone.
void callStateChanged(in unsigned long callIndex,
in unsigned short callState,
in AString number);
//XXX philikon's additions
void onoperatorchange(in jsval event);
void onradiostatechange(in jsval event);
void oncardstatechange(in jsval event);
void onsignalstrengthchange(in jsval event);
// 'callState' uses the CALL_STATE values from nsITelephone. Return true to
// continue enumeration or false to cancel.
boolean enumerateCallState(in unsigned long callIndex,
in unsigned short callState,
in AString number,
in boolean isActive);
};
[scriptable, uuid(5be6e41d-3aee-4f5c-8284-95cf529dd6fe)]
interface nsITelephone : nsISupports
{
const unsigned short CALL_STATE_UNKNOWN = 0;
const unsigned short CALL_STATE_DIALING = 1;
const unsigned short CALL_STATE_RINGING = 2;
const unsigned short CALL_STATE_BUSY = 3;
const unsigned short CALL_STATE_CONNECTING = 4;
const unsigned short CALL_STATE_CONNECTED = 5;
const unsigned short CALL_STATE_HOLDING = 6;
const unsigned short CALL_STATE_HELD = 7;
const unsigned short CALL_STATE_RESUMING = 8;
const unsigned short CALL_STATE_DISCONNECTING = 9;
const unsigned short CALL_STATE_DISCONNECTED = 10;
const unsigned short CALL_STATE_INCOMING = 11;
readonly attribute jsval currentState;
void registerCallback(in nsITelephoneCallback callback);
void unregisterCallback(in nsITelephoneCallback callback);
/**
* Will continue calling callback.enumerateCallState until the callback
* returns false.
*/
void enumerateCalls(in nsITelephoneCallback callback);
/**
* Functionality for making and managing phone calls.
*/
void dial(in DOMString number);
void hangUp(in long callIndex);
void hangUp(in unsigned long callIndex);
void startTone(in DOMString dtmfChar);
void stopTone();
void answerCall();
void rejectCall();
void answerCall(in unsigned long callIndex);
void rejectCall(in unsigned long callIndex);
attribute bool microphoneMuted;
attribute bool speakerEnabled;

Просмотреть файл

@ -36,26 +36,23 @@
*
* ***** END LICENSE BLOCK ***** */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var RIL = {};
Cu.import("resource://gre/modules/ril_consts.js", RIL);
const DEBUG = true; // set to false to suppress debug messages
const TELEPHONYWORKER_CONTRACTID = "@mozilla.org/telephony/worker;1";
const TELEPHONYWORKER_CID = Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
const DOM_CALL_READYSTATE_DIALING = "dialing";
const DOM_CALL_READYSTATE_RINGING = "ringing";
const DOM_CALL_READYSTATE_BUSY = "busy";
const DOM_CALL_READYSTATE_CONNECTING = "connecting";
const DOM_CALL_READYSTATE_CONNECTED = "connected";
const DOM_CALL_READYSTATE_DISCONNECTING = "disconnecting";
const DOM_CALL_READYSTATE_DISCONNECTED = "disconnected";
const DOM_CALL_READYSTATE_INCOMING = "incoming";
const DOM_CALL_READYSTATE_HOLDING = "holding";
const DOM_CALL_READYSTATE_HELD = "held";
const nsIAudioManager = Ci.nsIAudioManager;
const nsITelephone = Ci.nsITelephone;
const kSmsReceivedObserverTopic = "sms-received";
const DOM_SMS_DELIVERY_RECEIVED = "received";
@ -64,6 +61,25 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
"@mozilla.org/sms/smsservice;1",
"nsISmsService");
function convertRILCallState(state) {
switch (state) {
case RIL.CALL_STATE_ACTIVE:
return nsITelephone.CALL_STATE_CONNECTED;
case RIL.CALL_STATE_HOLDING:
return nsITelephone.CALL_STATE_HELD;
case RIL.CALL_STATE_DIALING:
return nsITelephone.CALL_STATE_DIALING;
case RIL.CALL_STATE_ALERTING:
return nsITelephone.CALL_STATE_RINGING;
case RIL.CALL_STATE_INCOMING:
return nsITelephone.CALL_STATE_INCOMING;
case RIL.CALL_STATE_WAITING:
return nsITelephone.CALL_STATE_HELD; // XXX This may not be right...
default:
throw new Error("Unknown rilCallState: " + state);
}
}
/**
* Fake nsIAudioManager implementation so that we can run the telephony
* code in a non-Gonk build.
@ -72,20 +88,20 @@ let FakeAudioManager = {
microphoneMuted: false,
masterVolume: 1.0,
masterMuted: false,
phoneState: Ci.nsIAudioManager.PHONE_STATE_CURRENT,
phoneState: nsIAudioManager.PHONE_STATE_CURRENT,
_forceForUse: {},
setForceForUse: function setForceForUse(usage, force) {
this._forceForUse[usage] = force;
},
getForceForUse: function setForceForUse(usage) {
return this._forceForUse[usage] || Ci.nsIAudioManager.FORCE_NONE;
return this._forceForUse[usage] || nsIAudioManager.FORCE_NONE;
}
};
XPCOMUtils.defineLazyGetter(this, "gAudioManager", function getAudioManager() {
try {
return Cc["@mozilla.org/telephony/audiomanager;1"]
.getService(Ci.nsIAudioManager);
.getService(nsIAudioManager);
} catch (ex) {
//TODO on the phone this should not fall back as silently.
debug("Using fake audio manager.");
@ -98,14 +114,12 @@ function nsTelephonyWorker() {
this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
this.worker.onerror = this.onerror.bind(this);
this.worker.onmessage = this.onmessage.bind(this);
this._callbacks = [];
debug("Starting Worker\n");
this.currentState = {
signalStrength: null,
operator: null,
radioState: null,
cardState: null,
currentCalls: {}
cardState: null
};
}
nsTelephonyWorker.prototype = {
@ -113,7 +127,7 @@ nsTelephonyWorker.prototype = {
classID: TELEPHONYWORKER_CID,
classInfo: XPCOMUtils.generateCI({classID: TELEPHONYWORKER_CID,
contractID: TELEPHONYWORKER_CONTRACTID,
classDescription: "TelephonyWorker",
classDescription: "Telephone",
interfaces: [Ci.nsIRadioWorker,
Ci.nsITelephone]}),
@ -121,18 +135,9 @@ nsTelephonyWorker.prototype = {
Ci.nsITelephone]),
onerror: function onerror(event) {
// It is very important to call preventDefault on the event here.
// If an exception is thrown on the worker, it bubbles out to the
// component that created it. If that component doesn't have an
// onerror handler, the worker will try to call the error reporter
// on the context it was created on. However, That doesn't work
// for component contexts and can result in crashes. This onerror
// handler has to make sure that it calls preventDefault on the
// incoming event.
event.preventDefault();
debug("Got an error: " + event.filename + ":" +
event.lineno + ": " + event.message + "\n");
event.preventDefault();
},
/**
@ -146,8 +151,19 @@ nsTelephonyWorker.prototype = {
onmessage: function onmessage(event) {
let message = event.data;
debug("Received message: " + JSON.stringify(message));
let value;
switch (message.type) {
case "callStateChange":
// This one will handle its own notifications.
this.handleCallStateChange(message.call);
break;
case "callDisconnected":
// This one will handle its own notifications.
this.handleCallDisconnected(message.call);
break;
case "enumerateCalls":
// This one will handle its own notifications.
this.handleEnumerateCalls(message.calls);
break;
case "signalstrengthchange":
this.currentState.signalStrength = message.signalStrength;
break;
@ -160,69 +176,100 @@ nsTelephonyWorker.prototype = {
case "cardstatechange":
this.currentState.cardState = message.cardState;
break;
case "callstatechange":
this.handleCallState(message);
break;
case "sms-received":
this.handleSmsReceived(message);
break;
return;
default:
// Got some message from the RIL worker that we don't know about.
return;
throw new Error("Don't know about this message type: " + message.type);
}
let methodname = "on" + message.type;
this._callbacks.forEach(function (callback) {
let method = callback[methodname];
if (typeof method != "function") {
return;
}
method.call(callback, message);
});
},
/**
* Handle call state changes by updating our current state and
* the audio system.
* Track the active call and update the audio system as its state changes.
*
* XXX Needs some more work to support hold/resume.
*/
handleCallState: function handleCallState(message) {
let currentCalls = this.currentState.currentCalls;
let oldState = currentCalls[message.callIndex];
// Update current state.
if (message.callState == DOM_CALL_READYSTATE_DISCONNECTED) {
delete currentCalls[message.callIndex];
} else {
currentCalls[message.callIndex] = message;
_activeCall: null,
get activeCall() {
return this._activeCall;
},
set activeCall(val) {
if (val && !this._activeCall) {
// Enable audio.
switch (val.state) {
case nsITelephone.CALL_STATE_INCOMING:
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
break;
case nsITelephone.CALL_STATE_DIALING: // Fall through...
case nsITelephone.CALL_STATE_CONNECTED:
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
nsIAudioManager.FORCE_NONE);
break;
default:
throw new Error("Invalid call state for active call: " + val.state);
}
} else if (!val && this._activeCall) {
// Disable audio.
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
}
this._activeCall = val;
},
// Update the audio system.
//TODO this does not handle multiple concurrent calls yet.
switch (message.callState) {
case DOM_CALL_READYSTATE_DIALING:
this.worker.postMessage({type: "setMute", mute: false});
gAudioManager.phoneState = Ci.nsIAudioManager.PHONE_STATE_IN_CALL;
gAudioManager.setForceForUse(Ci.nsIAudioManager.USE_COMMUNICATION,
Ci.nsIAudioManager.FORCE_NONE);
break;
case DOM_CALL_READYSTATE_INCOMING:
gAudioManager.phoneState = Ci.nsIAudioManager.PHONE_STATE_RINGTONE;
break;
case DOM_CALL_READYSTATE_CONNECTED:
if (!oldState ||
oldState.callState == DOM_CALL_READYSTATE_INCOMING ||
oldState.callState == DOM_CALL_READYSTATE_CONNECTING) {
// It's an incoming call, so tweak the audio now. If it was an
// outgoing call, it would have been tweaked at dialing.
this.worker.postMessage({type: "setMute", mute: false});
gAudioManager.phoneState = Ci.nsIAudioManager.PHONE_STATE_IN_CALL;
gAudioManager.setForceForUse(Ci.nsIAudioManager.USE_COMMUNICATION,
Ci.nsIAudioManager.FORCE_NONE);
}
break;
case DOM_CALL_READYSTATE_DISCONNECTED:
this.worker.postMessage({type: "setMute", mute: true});
gAudioManager.phoneState = Ci.nsIAudioManager.PHONE_STATE_NORMAL;
/**
* Handle call state changes by updating our current state and the audio
* system.
*/
handleCallStateChange: function handleCallStateChange(call) {
debug("handleCallStateChange: " + JSON.stringify(call));
call.state = convertRILCallState(call.state);
if (call.state == nsITelephone.CALL_STATE_INCOMING ||
call.state == nsITelephone.CALL_STATE_DIALING ||
call.state == nsITelephone.CALL_STATE_CONNECTED) {
// This is now the active call.
this.activeCall = call;
}
this._deliverCallback("callStateChanged",
[call.callIndex, call.state, call.number]);
},
/**
* Handle call disconnects by updating our current state and the audio system.
*/
handleCallDisconnected: function handleCallStateChange(call) {
debug("handleCallDisconnected: " + JSON.stringify(call));
if (this.activeCall == call) {
// No loner active.
this.activeCall = null;
}
this._deliverCallback("callStateChanged",
[call.callIndex, nsITelephone.CALL_STATE_DISCONNECTED,
call.number]);
},
/**
* Handle calls delivered in response to a 'enumerateCalls' request.
*/
handleEnumerateCalls: function handleEnumerateCalls(calls) {
debug("handleEnumerateCalls: " + JSON.stringify(calls));
let callback = this._enumerationCallbacks.shift();
let activeCallIndex = this.activeCall ? this.activeCall.callIndex : -1;
for (let i in calls) {
let call = calls[i];
let state = convertRILCallState(call.state);
let keepGoing;
try {
keepGoing =
callback.enumerateCallState(call.callIndex, state, call.number,
call.callIndex == activeCallIndex);
} catch (e) {
debug("callback handler for 'enumerateCallState' threw an " +
" exception: " + e);
keepGoing = true;
}
if (!keepGoing) {
break;
}
}
},
@ -265,12 +312,12 @@ nsTelephonyWorker.prototype = {
this.worker.postMessage({type: "stopTone"});
},
answerCall: function answerCall() {
this.worker.postMessage({type: "answerCall"});
answerCall: function answerCall(callIndex) {
this.worker.postMessage({type: "answerCall", callIndex: callIndex});
},
rejectCall: function rejectCall() {
this.worker.postMessage({type: "rejectCall"});
rejectCall: function rejectCall(callIndex) {
this.worker.postMessage({type: "rejectCall", callIndex: callIndex});
},
get microphoneMuted() {
@ -281,23 +328,23 @@ nsTelephonyWorker.prototype = {
return;
}
gAudioManager.phoneState = value ?
Ci.nsIAudioManager.PHONE_STATE_IN_COMMUNICATION :
Ci.nsIAudioManager.PHONE_STATE_IN_CALL; //XXX why is this needed?
nsIAudioManager.PHONE_STATE_IN_COMMUNICATION :
nsIAudioManager.PHONE_STATE_IN_CALL; //XXX why is this needed?
gAudioManager.microphoneMuted = value;
},
get speakerEnabled() {
return (gAudioManager.getForceForUse(Ci.nsIAudioManager.USE_COMMUNICATION)
== Ci.nsIAudioManager.FORCE_SPEAKER);
return (gAudioManager.getForceForUse(nsIAudioManager.USE_COMMUNICATION) ==
nsIAudioManager.FORCE_SPEAKER);
},
set speakerEnabled(value) {
if (value == this.speakerEnabled) {
return;
}
gAudioManager.phoneState = Ci.nsIAudioManager.PHONE_STATE_IN_CALL; // XXX why is this needed?
let force = value ? Ci.nsIAudioManager.FORCE_SPEAKER :
Ci.nsIAudioManager.FORCE_NONE;
gAudioManager.setForceUse(Ci.nsIAudioManager.USE_COMMUNICATION, force);
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL; // XXX why is this needed?
let force = value ? nsIAudioManager.FORCE_SPEAKER :
nsIAudioManager.FORCE_NONE;
gAudioManager.setForceUse(nsIAudioManager.USE_COMMUNICATION, force);
},
getNumberOfMessagesForText: function getNumberOfMessagesForText(text) {
@ -314,19 +361,63 @@ nsTelephonyWorker.prototype = {
},
_callbacks: null,
_enumerationCallbacks: null,
registerCallback: function registerCallback(callback) {
debug("Registering callback: " + callback);
if (this._callbacks) {
if (this._callbacks.indexOf(callback) != -1) {
throw new Error("Already registered this callback!");
}
} else {
this._callbacks = [];
}
this._callbacks.push(callback);
},
unregisterCallback: function unregisterCallback(callback) {
let index = this._callbacks.indexOf(callback);
if (index == -1) {
throw "Callback not registered!";
debug("Unregistering callback: " + callback);
let index;
if (this._callbacks && (index = this._callbacks.indexOf(callback) != -1)) {
this._callbacks.splice(index, 1);
}
this._callbacks.splice(index, 1);
},
enumerateCalls: function enumerateCalls(callback) {
debug("Requesting enumeration of calls for callback: " + callback);
this.worker.postMessage({type: "enumerateCalls"});
if (!this._enumerationCallbacks) {
this._enumerationCallbacks = [];
}
this._enumerationCallbacks.push(callback);
},
_deliverCallback: function _deliverCallback(name, args) {
// We need to worry about callback registration state mutations during the
// callback firing. The behaviour we want is to *not* call any callbacks
// that are added during the firing and to *not* call any callbacks that are
// removed during the firing. To address this, we make a copy of the
// callback list before dispatching and then double-check that each callback
// is still registered before calling it.
if (!this._callbacks) {
return;
}
let callbacks = this._callbacks.slice();
for each (let callback in callbacks) {
if (this._callbacks.indexOf(callback) == -1) {
continue;
}
let handler = callback[name];
if (typeof handler != "function") {
throw new Error("No handler for " + name);
}
try {
handler.apply(callback, args);
} catch (e) {
debug("callback handler for " + name + " threw an exception: " + e);
}
}
},
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsTelephonyWorker]);

Просмотреть файл

@ -225,26 +225,6 @@ const DOM_CARDSTATE_NETWORK_LOCKED = "network_locked";
const DOM_CARDSTATE_NOT_READY = "not_ready";
const DOM_CARDSTATE_READY = "ready";
const DOM_CALL_READYSTATE_DIALING = "dialing";
const DOM_CALL_READYSTATE_RINGING = "ringing";
const DOM_CALL_READYSTATE_BUSY = "busy";
const DOM_CALL_READYSTATE_CONNECTING = "connecting";
const DOM_CALL_READYSTATE_CONNECTED = "connected";
const DOM_CALL_READYSTATE_DISCONNECTING = "disconnecting";
const DOM_CALL_READYSTATE_DISCONNECTED = "disconnected";
const DOM_CALL_READYSTATE_INCOMING = "incoming";
const DOM_CALL_READYSTATE_HOLDING = "holding";
const DOM_CALL_READYSTATE_HELD = "held";
const RIL_TO_DOM_CALL_STATE = [
DOM_CALL_READYSTATE_CONNECTED, // CALL_READYSTATE_ACTIVE
DOM_CALL_READYSTATE_HELD, // CALL_READYSTATE_HOLDING
DOM_CALL_READYSTATE_DIALING, // CALL_READYSTATE_DIALING
DOM_CALL_READYSTATE_RINGING, // CALL_READYSTATE_ALERTING
DOM_CALL_READYSTATE_INCOMING, // CALL_READYSTATE_INCOMING
DOM_CALL_READYSTATE_HELD // CALL_READYSTATE_WAITING (XXX is this right?)
];
/**
* GSM PDU constants
@ -413,3 +393,7 @@ const PDU_ALPHABET_7BIT_DEFAULT = [
"\xfc", // LATIN SMALL LETTER U WITH DIAERESIS
"\xe0" // LATIN SMALL LETTER A WITH GRAVE
];
// Allow this file to be imported via Components.utils.import().
const EXPORTED_SYMBOLS = Object.keys(this);

Просмотреть файл

@ -628,13 +628,13 @@ let RIL = {
/**
* Hang up the phone.
*
* @param index
* @param callIndex
* Call index (1-based) as reported by REQUEST_GET_CURRENT_CALLS.
*/
hangUp: function hangUp(index) {
hangUp: function hangUp(callIndex) {
Buf.newParcel(REQUEST_HANGUP);
Buf.writeUint32(1);
Buf.writeUint32(index);
Buf.writeUint32(callIndex);
Buf.sendParcel();
},
@ -819,7 +819,7 @@ RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length) {
for (let i = 0; i < calls_length; i++) {
let call = {
state: Buf.readUint32(), // CALL_STATE_*
index: Buf.readUint32(), // GSM index (1-based)
callIndex: Buf.readUint32(), // GSM index (1-based)
toa: Buf.readUint32(),
isMpty: Boolean(Buf.readUint32()),
isMT: Boolean(Buf.readUint32()),
@ -841,7 +841,7 @@ RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length) {
userData: null //XXX TODO byte array?!?
};
}
calls[call.index] = call;
calls[call.callIndex] = call;
}
Phone.onCurrentCalls(calls);
};
@ -1122,6 +1122,38 @@ let Phone = {
*/
currentCalls: {},
/**
* Mute or unmute the radio.
*/
_muted: true,
get muted() {
return this._muted;
},
set muted(val) {
val = Boolean(val);
if (this._muted != val) {
RIL.setMute(val);
this._muted = val;
}
},
_handleChangedCallState: function _handleChangedCallState(changedCall) {
let message = {type: "callStateChange",
call: {callIndex: changedCall.callIndex,
state: changedCall.state,
number: changedCall.number,
name: changedCall.name}};
this.sendDOMMessage(message);
},
_handleDisconnectedCall: function _handleDisconnectedCall(disconnectedCall) {
let message = {type: "callDisconnected",
call: {callIndex: disconnectedCall.callIndex}};
this.sendDOMMessage(message);
},
/**
* Handlers for messages from the RIL. They all begin with on* and are called
* from RIL object.
@ -1218,53 +1250,46 @@ let Phone = {
// changed state. Remove them from the newCalls map as we deal with them
// so that only new calls remain in the map after we're done.
for each (let currentCall in this.currentCalls) {
let callIndex = currentCall.index;
let newCall;
if (newCalls) {
newCall = newCalls[callIndex];
delete newCalls[callIndex];
newCall = newCalls[currentCall.callIndex];
delete newCalls[currentCall.callIndex];
}
if (!newCall) {
// Call is no longer reported by the radio. Send disconnected
// state change.
this.sendDOMMessage({type: "callstatechange",
callState: DOM_CALL_READYSTATE_DISCONNECTED,
callIndex: callIndex,
number: currentCall.number,
name: currentCall.name});
delete this.currentCalls[callIndex];
continue;
if (newCall) {
// Call is still valid.
if (newCall.state != currentCall.state) {
// State has changed.
currentCall.state = newCall.state;
this._handleChangedCallState(currentCall);
}
}
if (newCall.state == currentCall.state) {
continue;
else {
// Call is no longer reported by the radio. Remove from our map and
// send disconnected state change.
delete this.currentCalls[currentCall.callIndex];
this._handleDisconnectedCall(currentCall);
}
this._handleChangedCallState(newCall);
}
// Go through any remaining calls that are new to us.
for each (let newCall in newCalls) {
if (newCall.isVoice) {
// Format international numbers appropriately.
if (newCall.number &&
newCall.toa == TOA_INTERNATIONAL &&
newCall.number[0] != "+") {
newCall.number = "+" + newCall.number;
}
// Add to our map.
this.currentCalls[newCall.callIndex] = newCall;
this._handleChangedCallState(newCall);
}
}
},
_handleChangedCallState: function handleChangedCallState(newCall) {
// Format international numbers appropriately.
if (newCall.number &&
newCall.toa == TOA_INTERNATIONAL &&
newCall.number[0] != "+") {
newCall.number = "+" + newCall.number;
}
this.currentCalls[newCall.index] = newCall;
this.sendDOMMessage({type: "callstatechange",
callState: RIL_TO_DOM_CALL_STATE[newCall.state],
callIndex: newCall.index,
number: newCall.number,
name: newCall.name});
// Update our mute status. If there is anything in our currentCalls map then
// we know it's a voice call and we should leave audio on.
this.muted = Object.getOwnPropertyNames(this.currentCalls).length == 0;
},
onCallStateChanged: function onCallStateChanged() {
@ -1447,6 +1472,18 @@ let Phone = {
RIL.getNetworkSelectionMode();
},
/**
* Get a list of current voice calls.
*/
enumerateCalls: function enumerateCalls() {
if (DEBUG) debug("Sending all current calls");
let calls = [];
for each (let call in this.currentCalls) {
calls.push(call);
}
this.sendDOMMessage({type: "enumerateCalls", calls: calls});
},
/**
* Dial the phone.
*
@ -1496,30 +1533,38 @@ let Phone = {
RIL.hangUp(options.callIndex);
},
/**
* Mute or unmute the radio.
*
* @param mute
* Boolean to indicate whether to mute or unmute the radio.
*/
setMute: function setMute(options) {
//TODO need to check whether call is holding/waiting/background
// and then use REQUEST_HANGUP_WAITING_OR_BACKGROUND
RIL.setMute(options.mute);
},
/**
* Answer an incoming call.
*
* @param callIndex
* Call index of the call to answer.
*/
answerCall: function answerCall() {
RIL.answerCall();
answerCall: function answerCall(options) {
// Check for races. Since we dispatched the incoming call notification the
// incoming call may have changed. The main thread thinks that it is
// answering the call with the given index, so only answer if that is still
// incoming.
let call = this.currentCalls[options.callIndex];
if (call && call.state == CALL_STATE_INCOMING) {
RIL.answerCall();
}
},
/**
* Reject an incoming call.
*
* @param callIndex
* Call index of the call to reject.
*/
rejectCall: function rejectCall() {
RIL.rejectCall();
rejectCall: function rejectCall(options) {
// Check for races. Since we dispatched the incoming call notification the
// incoming call may have changed. The main thread thinks that it is
// rejecting the call with the given index, so only reject if that is still
// incoming.
let call = this.currentCalls[options.callIndex];
if (call && call.state == CALL_STATE_INCOMING) {
RIL.rejectCall();
}
},
/**

Просмотреть файл

@ -504,6 +504,8 @@ irregularFilenames = {
'nsIDOMTouch': 'nsIDOMTouchEvent',
'nsIDOMTouchList': 'nsIDOMTouchEvent',
'nsITelephoneCallback': 'nsITelephone',
}
customIncludes = [