Bug 694862 - Implement navigator.mozVibrate for Gonk, r=cjones

This commit is contained in:
Justin Lebar 2011-12-21 17:58:29 -08:00
Родитель 4f181e1a2e
Коммит 1304408f8f
1 изменённых файлов: 148 добавлений и 6 удалений

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

@ -45,6 +45,15 @@
#include "mozilla/FileUtils.h"
#include "nsAlgorithm.h"
#include "nsThreadUtils.h"
#include "mozilla/Monitor.h"
#include "mozilla/Services.h"
#include "mozilla/FileUtils.h"
#include "nsThreadUtils.h"
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "hardware_legacy/vibrator.h"
#include <stdio.h>
#include <math.h>
#include <fcntl.h>
@ -55,13 +64,146 @@ using mozilla::hal::WindowIdentifier;
namespace mozilla {
namespace hal_impl {
void
Vibrate(const nsTArray<uint32>& pattern, const WindowIdentifier &)
{}
namespace {
/**
* This runnable runs for the lifetime of the program, once started. It's
* responsible for "playing" vibration patterns.
*/
class VibratorRunnable
: public nsIRunnable
, public nsIObserver
{
public:
VibratorRunnable()
: mMonitor("VibratorRunnable")
, mIndex(0)
, mShuttingDown(false)
{
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (!os) {
NS_WARNING("Could not get observer service!");
return;
}
os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, /* weak ref */ true);
}
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSIOBSERVER
// Run on the main thread, not the vibrator thread.
void Vibrate(const nsTArray<uint32> &pattern);
void CancelVibrate();
private:
Monitor mMonitor;
// The currently-playing pattern.
nsTArray<uint32> mPattern;
// The index we're at in the currently-playing pattern. If mIndex >=
// mPattern.Length(), then we're not currently playing anything.
uint32 mIndex;
// Set to true in our shutdown observer. When this is true, we kill the
// vibrator thread.
bool mShuttingDown;
};
NS_IMPL_ISUPPORTS2(VibratorRunnable, nsIRunnable, nsIObserver);
NS_IMETHODIMP
VibratorRunnable::Run()
{
MonitorAutoLock lock(mMonitor);
// We currently assume that mMonitor.Wait(X) waits for X milliseconds. But in
// reality, the kernel might not switch to this thread for some time after the
// wait expires. So there's potential for some inaccuracy here.
//
// This doesn't worry me too much. Note that we don't even start vibrating
// immediately when VibratorRunnable::Vibrate is called -- we go through a
// condvar onto another thread. Better just to be chill about small errors in
// the timing here.
while (!mShuttingDown) {
if (mIndex < mPattern.Length()) {
uint32 duration = mPattern[mIndex];
if (mIndex % 2 == 0) {
vibrator_on(duration);
}
mIndex++;
mMonitor.Wait(PR_MillisecondsToInterval(duration));
}
else {
mMonitor.Wait();
}
}
return NS_OK;
}
NS_IMETHODIMP
VibratorRunnable::Observe(nsISupports *subject, const char *topic,
const PRUnichar *data)
{
MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
MonitorAutoLock lock(mMonitor);
mShuttingDown = true;
mMonitor.Notify();
return NS_OK;
}
void
CancelVibrate(const WindowIdentifier &)
{}
VibratorRunnable::Vibrate(const nsTArray<uint32> &pattern)
{
MonitorAutoLock lock(mMonitor);
mPattern = pattern;
mIndex = 0;
mMonitor.Notify();
}
void
VibratorRunnable::CancelVibrate()
{
MonitorAutoLock lock(mMonitor);
mPattern.Clear();
mPattern.AppendElement(0);
mIndex = 0;
mMonitor.Notify();
}
VibratorRunnable *sVibratorRunnable = NULL;
void
EnsureVibratorThreadInitialized()
{
if (sVibratorRunnable) {
return;
}
nsRefPtr<VibratorRunnable> runnable = new VibratorRunnable();
sVibratorRunnable = runnable;
nsCOMPtr<nsIThread> thread;
NS_NewThread(getter_AddRefs(thread), sVibratorRunnable);
}
} // anonymous namespace
void
Vibrate(const nsTArray<uint32> &pattern, const hal::WindowIdentifier &)
{
EnsureVibratorThreadInitialized();
sVibratorRunnable->Vibrate(pattern);
}
void
CancelVibrate(const hal::WindowIdentifier &)
{
EnsureVibratorThreadInitialized();
sVibratorRunnable->CancelVibrate();
}
namespace {
@ -143,7 +285,7 @@ DisableBatteryNotifications()
}
void
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
GetCurrentBatteryInformation(hal::BatteryInformation *aBatteryInfo)
{
FILE *capacityFile = fopen("/sys/class/power_supply/battery/capacity", "r");
double capacity = dom::battery::kDefaultLevel * 100;