Bug 734855 - Device Orientation - Make EnableDeviceMotion finer grain. r=mwu

This commit is contained in:
Doug Turner 2012-03-24 17:29:49 -07:00
Родитель e2439e77a8
Коммит b2d8db07c0
7 изменённых файлов: 143 добавлений и 202 удалений

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

@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/Hal.h"
#include "mozilla/HalSensor.h"
#include "nsISupports.h"
#include "nsGUIEvent.h"
#include "nsDOMEvent.h"
@ -85,6 +87,7 @@
#include "sampler.h"
using namespace mozilla::dom;
using namespace mozilla::hal;
#define EVENT_TYPE_EQUALS( ls, type, userType ) \
(ls->mEventType == type && \
@ -282,11 +285,17 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
kAllMutationBits :
MutationBitForEventType(aType));
}
} else if (aTypeAtom == nsGkAtoms::ondeviceorientation ||
aTypeAtom == nsGkAtoms::ondevicemotion) {
} else if (aTypeAtom == nsGkAtoms::ondeviceorientation) {
nsPIDOMWindow* window = GetInnerWindowForTarget();
if (window)
window->EnableDeviceSensor(SENSOR_ORIENTATION);
} else if (aTypeAtom == nsGkAtoms::ondevicemotion) {
nsPIDOMWindow* window = GetInnerWindowForTarget();
if (window)
window->SetHasOrientationEventListener();
if (window) {
window->EnableDeviceSensor(SENSOR_ACCELERATION);
window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
window->EnableDeviceSensor(SENSOR_GYROSCOPE);
}
} else if ((aType >= NS_MOZTOUCH_DOWN && aType <= NS_MOZTOUCH_UP) ||
(aTypeAtom == nsGkAtoms::ontouchstart ||
aTypeAtom == nsGkAtoms::ontouchend ||
@ -340,7 +349,14 @@ nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener,
if (aType == NS_DEVICE_ORIENTATION) {
nsPIDOMWindow* window = GetInnerWindowForTarget();
if (window)
window->RemoveOrientationEventListener();
window->DisableDeviceSensor(SENSOR_ORIENTATION);
} else if (aType == NS_DEVICE_MOTION) {
nsPIDOMWindow* window = GetInnerWindowForTarget();
if (window) {
window->DisableDeviceSensor(SENSOR_ACCELERATION);
window->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
window->DisableDeviceSensor(SENSOR_GYROSCOPE);
}
}
break;
}

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

@ -882,7 +882,6 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
#endif
mShowFocusRingForContent(false),
mFocusByKeyOccurred(false),
mHasDeviceMotion(false),
mNotifiedIDDestroyed(false),
mTimeoutInsertionPoint(nsnull),
mTimeoutPublicIdCounter(1),
@ -1113,8 +1112,9 @@ nsGlobalWindow::~nsGlobalWindow()
mURLProperty->ClearWindowReference();
}
DisableDeviceMotionUpdates();
mHasDeviceMotion = false;
nsCOMPtr<nsIDeviceMotion> ac = do_GetService(NS_DEVICE_MOTION_CONTRACTID);
if (ac)
ac->RemoveWindowAsListener(this);
nsLayoutStatics::Release();
}
@ -7810,30 +7810,6 @@ void nsGlobalWindow::UpdateTouchState()
}
}
void
nsGlobalWindow::EnableDeviceMotionUpdates()
{
if (mHasDeviceMotion) {
nsCOMPtr<nsIDeviceMotion> ac =
do_GetService(NS_DEVICE_MOTION_CONTRACTID);
if (ac) {
ac->AddWindowListener(this);
}
}
}
void
nsGlobalWindow::DisableDeviceMotionUpdates()
{
if (mHasDeviceMotion) {
nsCOMPtr<nsIDeviceMotion> ac =
do_GetService(NS_DEVICE_MOTION_CONTRACTID);
if (ac) {
ac->RemoveWindowListener(this);
}
}
}
void
nsGlobalWindow::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
{
@ -10143,7 +10119,11 @@ nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
mTimeoutsSuspendDepth += aIncrease;
if (!suspended) {
DisableDeviceMotionUpdates();
nsCOMPtr<nsIDeviceMotion> ac = do_GetService(NS_DEVICE_MOTION_CONTRACTID);
if (ac) {
for (int i = 0; i < mEnabledSensors.Length(); i++)
ac->RemoveWindowListener(mEnabledSensors[i], this);
}
// Suspend all of the workers for this window.
nsIScriptContext *scx = GetContextInternal();
@ -10219,7 +10199,11 @@ nsGlobalWindow::ResumeTimeouts(bool aThawChildren)
nsresult rv;
if (shouldResume) {
EnableDeviceMotionUpdates();
nsCOMPtr<nsIDeviceMotion> ac = do_GetService(NS_DEVICE_MOTION_CONTRACTID);
if (ac) {
for (int i = 0; i < mEnabledSensors.Length(); i++)
ac->AddWindowListener(mEnabledSensors[i], this);
}
// Resume all of the workers for this window.
nsIScriptContext *scx = GetContextInternal();
@ -10322,15 +10306,45 @@ nsGlobalWindow::TimeoutSuspendCount()
}
void
nsGlobalWindow::SetHasOrientationEventListener()
nsGlobalWindow::EnableDeviceSensor(PRUint32 aType)
{
mHasDeviceMotion = true;
EnableDeviceMotionUpdates();
bool alreadyEnabled = false;
for (int i = 0; i < mEnabledSensors.Length(); i++) {
if (mEnabledSensors[i] == aType) {
alreadyEnabled = true;
break;
}
}
if (alreadyEnabled)
return;
mEnabledSensors.AppendElement(aType);
nsCOMPtr<nsIDeviceMotion> ac = do_GetService(NS_DEVICE_MOTION_CONTRACTID);
if (ac)
ac->AddWindowListener(aType, this);
}
void
nsGlobalWindow::RemoveOrientationEventListener() {
DisableDeviceMotionUpdates();
nsGlobalWindow::DisableDeviceSensor(PRUint32 aType)
{
PRUint32 doomedElement = -1;
for (int i = 0; i < mEnabledSensors.Length(); i++) {
if (mEnabledSensors[i] == aType) {
doomedElement = -1;
break;
}
}
if (doomedElement == -1)
return;
mEnabledSensors.RemoveElementAt(doomedElement);
nsCOMPtr<nsIDeviceMotion> ac = do_GetService(NS_DEVICE_MOTION_CONTRACTID);
if (ac)
ac->RemoveWindowListener(aType, this);
}
NS_IMETHODIMP

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

@ -373,8 +373,6 @@ public:
virtual NS_HIDDEN_(bool) CanClose();
virtual NS_HIDDEN_(nsresult) ForceClose();
virtual NS_HIDDEN_(void) SetHasOrientationEventListener();
virtual NS_HIDDEN_(void) RemoveOrientationEventListener();
virtual NS_HIDDEN_(void) MaybeUpdateTouchState();
virtual NS_HIDDEN_(void) UpdateTouchState();
virtual NS_HIDDEN_(bool) DispatchCustomEvent(const char *aEventName);
@ -519,6 +517,10 @@ public:
virtual nsresult DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI);
virtual nsresult DispatchSyncPopState();
virtual void EnableDeviceSensor(PRUint32 aType);
virtual void DisableDeviceSensor(PRUint32 aType);
nsTArray<PRUint32> mEnabledSensors;
virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
static bool DOMWindowDumpEnabled();
@ -573,12 +575,6 @@ public:
void AddEventTargetObject(nsDOMEventTargetHelper* aObject);
void RemoveEventTargetObject(nsDOMEventTargetHelper* aObject);
private:
// Enable updates for the accelerometer.
void EnableDeviceMotionUpdates();
// Disables updates for the accelerometer.
void DisableDeviceMotionUpdates();
// Implements Get{Real,Scriptable}Top.
nsresult GetTopImpl(nsIDOMWindow **aWindow, bool aScriptable);
@ -893,9 +889,6 @@ protected:
// should be displayed.
bool mFocusByKeyOccurred : 1;
// Indicates whether this window is getting device motion change events
bool mHasDeviceMotion : 1;
// whether we've sent the destroy notification for our window id
bool mNotifiedIDDestroyed : 1;

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

@ -575,14 +575,14 @@ public:
virtual nsresult DispatchSyncPopState() = 0;
/**
* Tell this window that there is an observer for orientation changes
* Tell this window that it should listen for sensor changes of the given type.
*/
virtual void SetHasOrientationEventListener() = 0;
virtual void EnableDeviceSensor(PRUint32 aType) = 0;
/**
* Tell this window that we remove an orientation listener
* Tell this window that it should remove itself from sensor change notifications.
*/
virtual void RemoveOrientationEventListener() = 0;
virtual void DisableDeviceSensor(PRUint32 aType) = 0;
/**
* Set a arguments for this window. This will be set on the window

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

@ -57,7 +57,7 @@ using namespace hal;
#define DEFAULT_SENSOR_POLL 100
static const nsTArray<nsIDOMWindow*>::index_type NoIndex =
nsTArray<nsIDOMWindow*>::NoIndex;
nsTArray<nsIDOMWindow*>::NoIndex;
class nsDeviceMotionData : public nsIDeviceMotionData
{
@ -122,8 +122,7 @@ NS_IMETHODIMP nsDeviceMotionData::GetZ(double *aZ)
NS_IMPL_ISUPPORTS1(nsDeviceMotion, nsIDeviceMotion)
nsDeviceMotion::nsDeviceMotion()
: mStarted(false),
mEnabled(true)
: mEnabled(true)
{
mLastDOMMotionEventTime = TimeStamp::Now();
@ -134,96 +133,55 @@ nsDeviceMotion::nsDeviceMotion()
if (NS_SUCCEEDED(rv) && bvalue == false)
mEnabled = false;
}
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
nsTArray<nsIDOMWindow*> *windows = new nsTArray<nsIDOMWindow*>();
mWindowListeners.AppendElement(windows);
}
mLastDOMMotionEventTime = TimeStamp::Now();
}
nsDeviceMotion::~nsDeviceMotion()
{
if (mStarted)
Shutdown();
if (mTimeoutTimer)
mTimeoutTimer->Cancel();
}
void
nsDeviceMotion::StartDisconnectTimer()
{
if (mTimeoutTimer)
mTimeoutTimer->Cancel();
mTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mTimeoutTimer)
mTimeoutTimer->InitWithFuncCallback(TimeoutHandler,
this,
2000,
nsITimer::TYPE_ONE_SHOT);
}
void
nsDeviceMotion::TimeoutHandler(nsITimer *aTimer, void *aClosure)
{
// the reason that we use self, instead of just using nsITimerCallback or nsIObserver
// is so that subclasses are free to use timers without worry about the base classes's
// usage.
nsDeviceMotion *self = reinterpret_cast<nsDeviceMotion *>(aClosure);
if (!self) {
NS_ERROR("no self");
return;
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
if (IsSensorEnabled(i))
UnregisterSensorObserver((SensorType)i, this);
}
// what about listeners that don't clean up properly? they will leak
if (self->mListeners.Count() == 0 && self->mWindowListeners.Length() == 0) {
self->Shutdown();
self->mStarted = false;
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
delete mWindowListeners[i];
}
}
NS_IMETHODIMP nsDeviceMotion::AddListener(nsIDeviceMotionListener *aListener)
NS_IMETHODIMP nsDeviceMotion::AddWindowListener(PRUint32 aType, nsIDOMWindow *aWindow)
{
if (mListeners.IndexOf(aListener) != -1)
return NS_OK; // already exists
if (mStarted == false) {
mStarted = true;
Startup();
}
mListeners.AppendObject(aListener);
return NS_OK;
}
NS_IMETHODIMP nsDeviceMotion::RemoveListener(nsIDeviceMotionListener *aListener)
{
if (mListeners.IndexOf(aListener) == -1)
return NS_OK; // doesn't exist
mListeners.RemoveObject(aListener);
StartDisconnectTimer();
return NS_OK;
}
NS_IMETHODIMP nsDeviceMotion::AddWindowListener(nsIDOMWindow *aWindow)
{
if (mWindowListeners.IndexOf(aWindow) != NoIndex)
return NS_OK;
if (mStarted == false) {
mStarted = true;
Startup();
}
mWindowListeners.AppendElement(aWindow);
return NS_OK;
}
NS_IMETHODIMP nsDeviceMotion::RemoveWindowListener(nsIDOMWindow *aWindow)
{
if (mWindowListeners.IndexOf(aWindow) == NoIndex)
if (mWindowListeners[aType]->IndexOf(aWindow) != NoIndex)
return NS_OK;
mWindowListeners.RemoveElement(aWindow);
StartDisconnectTimer();
if (!IsSensorEnabled(aType)) {
RegisterSensorObserver((SensorType)aType, this);
}
mWindowListeners[aType]->AppendElement(aWindow);
return NS_OK;
}
NS_IMETHODIMP nsDeviceMotion::RemoveWindowListener(PRUint32 aType, nsIDOMWindow *aWindow)
{
if (mWindowListeners[aType]->IndexOf(aWindow) == NoIndex)
return NS_OK;
mWindowListeners[aType]->RemoveElement(aWindow);
return NS_OK;
}
NS_IMETHODIMP nsDeviceMotion::RemoveWindowAsListener(nsIDOMWindow *aWindow)
{
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
if (IsSensorEnabled(i))
RemoveWindowListener((SensorType)i, aWindow);
}
return NS_OK;
}
@ -239,16 +197,9 @@ nsDeviceMotion::Notify(const mozilla::hal::SensorData& aSensorData)
double y = aSensorData.values()[1];
double z = aSensorData.values()[2];
nsCOMArray<nsIDeviceMotionListener> listeners = mListeners;
for (PRUint32 i = listeners.Count(); i > 0 ; ) {
--i;
nsRefPtr<nsDeviceMotionData> a = new nsDeviceMotionData(type, x, y, z);
listeners[i]->OnMotionChange(a);
}
nsCOMArray<nsIDOMWindow> windowListeners;
for (PRUint32 i = 0; i < mWindowListeners.Length(); i++) {
windowListeners.AppendObject(mWindowListeners[i]);
for (PRUint32 i = 0; i < mWindowListeners[type]->Length(); i++) {
windowListeners.AppendObject(mWindowListeners[type]->SafeElementAt(i));
}
for (PRUint32 i = windowListeners.Count(); i > 0 ; ) {
@ -269,7 +220,7 @@ nsDeviceMotion::Notify(const mozilla::hal::SensorData& aSensorData)
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(windowListeners[i]);
if (type == nsIDeviceMotionData::TYPE_ACCELERATION ||
type == nsIDeviceMotionData::TYPE_LINEAR_ACCELERATION ||
type == nsIDeviceMotionData::TYPE_GYROSCOPE)
type == nsIDeviceMotionData::TYPE_GYROSCOPE)
FireDOMMotionEvent(domdoc, target, type, x, y, z);
else if (type == nsIDeviceMotionData::TYPE_ORIENTATION)
FireDOMOrientationEvent(domdoc, target, x, y, z);
@ -322,18 +273,18 @@ nsDeviceMotion::FireDOMMotionEvent(nsIDOMDocument *domdoc,
switch (type) {
case nsIDeviceMotionData::TYPE_LINEAR_ACCELERATION:
mLastAcceleration = new nsDOMDeviceAcceleration(x, y, z);
break;
mLastAcceleration = new nsDOMDeviceAcceleration(x, y, z);
break;
case nsIDeviceMotionData::TYPE_ACCELERATION:
mLastAccelerationIncluduingGravity = new nsDOMDeviceAcceleration(x, y, z);
break;
mLastAccelerationIncluduingGravity = new nsDOMDeviceAcceleration(x, y, z);
break;
case nsIDeviceMotionData::TYPE_GYROSCOPE:
mLastRotationRate = new nsDOMDeviceRotationRate(x, y, z);
break;
mLastRotationRate = new nsDOMDeviceRotationRate(x, y, z);
break;
}
if (!fireEvent && (!mLastAcceleration || !mLastAccelerationIncluduingGravity || !mLastRotationRate)) {
return;
return;
}
nsCOMPtr<nsIDOMEvent> event;
@ -341,9 +292,8 @@ nsDeviceMotion::FireDOMMotionEvent(nsIDOMDocument *domdoc,
nsCOMPtr<nsIDOMDeviceMotionEvent> me = do_QueryInterface(event);
if (!me) {
if (!me)
return;
}
me->InitDeviceMotionEvent(NS_LITERAL_STRING("devicemotion"),
true,
@ -356,7 +306,7 @@ nsDeviceMotion::FireDOMMotionEvent(nsIDOMDocument *domdoc,
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
if (privateEvent)
privateEvent->SetTrusted(true);
bool defaultActionEnabled = true;
target->DispatchEvent(event, &defaultActionEnabled);
@ -365,22 +315,3 @@ nsDeviceMotion::FireDOMMotionEvent(nsIDOMDocument *domdoc,
mLastAcceleration = nsnull;
mLastDOMMotionEventTime = TimeStamp::Now();
}
void nsDeviceMotion::Startup()
{
// Bug 734855 - we probably can make this finer grain
// based on the DOM APIs that are being invoked.
RegisterSensorObserver(SENSOR_ACCELERATION, this);
RegisterSensorObserver(SENSOR_ORIENTATION, this);
RegisterSensorObserver(SENSOR_LINEAR_ACCELERATION, this);
RegisterSensorObserver(SENSOR_GYROSCOPE, this);
}
void nsDeviceMotion::Shutdown()
{
UnregisterSensorObserver(SENSOR_ACCELERATION, this);
UnregisterSensorObserver(SENSOR_ORIENTATION, this);
UnregisterSensorObserver(SENSOR_LINEAR_ACCELERATION, this);
UnregisterSensorObserver(SENSOR_GYROSCOPE, this);
}

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

@ -48,7 +48,7 @@
#include "nsDOMDeviceMotionEvent.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/HalSensor.h"
#include "nsDataHashtable.h"
#define NS_DEVICE_MOTION_CID \
{ 0xecba5203, 0x77da, 0x465a, \
@ -71,17 +71,12 @@ public:
void Notify(const mozilla::hal::SensorData& aSensorData);
private:
nsCOMArray<nsIDeviceMotionListener> mListeners;
nsTArray<nsIDOMWindow*> mWindowListeners;
// sensor -> window listener
nsTArray<nsTArray<nsIDOMWindow*>* > mWindowListeners;
// window -> sensortype enabled
nsDataHashtable<nsUint32HashKey, nsTArray<PRUint32 > > mSensorsEnabled;
void StartDisconnectTimer();
bool mStarted;
nsCOMPtr<nsITimer> mTimeoutTimer;
static void TimeoutHandler(nsITimer *aTimer, void *aClosure);
protected:
void FireDOMOrientationEvent(class nsIDOMDocument *domDoc,
class nsIDOMEventTarget *target,
double alpha,
@ -95,10 +90,12 @@ private:
double y,
double z);
void Startup();
void Shutdown();
bool mEnabled;
inline bool IsSensorEnabled(PRUint32 aType) {
return mWindowListeners[aType]->Length() > 0;
}
mozilla::TimeStamp mLastDOMMotionEventTime;
nsRefPtr<nsDOMDeviceAcceleration> mLastAcceleration;
nsRefPtr<nsDOMDeviceAcceleration> mLastAccelerationIncluduingGravity;

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

@ -55,22 +55,12 @@ interface nsIDeviceMotionData : nsISupports
readonly attribute double z;
};
[scriptable, uuid(D29EA788-CCB6-4875-88E0-32A34BB71CBB)]
interface nsIDeviceMotionListener : nsISupports
{
void onMotionChange(in nsIDeviceMotionData aMotionData);
void needsCalibration();
};
[scriptable, uuid(B6E5C463-AAA6-44E2-BD07-7A7DC6192E68)]
[scriptable, uuid(b672bfe0-4479-4094-a9ef-1b6847720d07)]
interface nsIDeviceMotion : nsISupports
{
void addListener(in nsIDeviceMotionListener aListener);
void removeListener(in nsIDeviceMotionListener aListener);
// Holds pointers, not AddRef objects -- it is up to the caller
// to call RemoveWindowListener before the window is deleted.
[noscript] void addWindowListener(in nsIDOMWindow aWindow);
[noscript] void removeWindowListener(in nsIDOMWindow aWindow);
[noscript] void addWindowListener(in unsigned long aType, in nsIDOMWindow aWindow);
[noscript] void removeWindowListener(in unsigned long aType, in nsIDOMWindow aWindow);
[noscript] void removeWindowAsListener(in nsIDOMWindow aWindow);
};