зеркало из https://github.com/mozilla/pjs.git
Bug 694862 - Implement navigator.mozVibrate for Gonk, r=cjones
This commit is contained in:
Родитель
4f181e1a2e
Коммит
1304408f8f
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче