Commit c457d068 authored by alexander.shalamov's avatar alexander.shalamov Committed by Commit bot

[sensors] Ambient light sensor bindings implementation

This patch implements AmbientLightSensor [1] blink bindings and adds
LayoutTest helpers for testing sensors that are based on Generic Sensor API.

Following layout tests added to test new functionality:
IDL tests.
 - third_party/WebKit/LayoutTests/sensor/idl-AmbientLightSensor.html
 - third_party/WebKit/LayoutTests/sensor/idl-AmbientLightSensorReading.html
AmbientLightSensor tests.
 - third_party/WebKit/LayoutTests/sensor/ambient-light-sensor.html

Intent to Implement:
https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/TkfdVqYAYiE/xLGN2b1-AAAJ

[1] ED specification for Ambient Light Sensor http://w3c.github.io/ambient-light/

BUG=606766

Review-Url: https://codereview.chromium.org/2332323002
Cr-Commit-Position: refs/heads/master@{#419438}
parent 452fd4f3
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="../resources/mojo-helpers.js"></script>
<script src="resources/sensor-helpers.js"></script>
<script>
'use strict';
if (!window.testRunner)
debug('This test cannot be run without the TestRunner');
const kDefaultReadingValue = 3.1415;
function update_sensor_reading(buffer) {
buffer[0] = window.performance.now();
buffer[1] = kDefaultReadingValue;
}
sensor_test(sensor => {
let ambientLightSensor = new AmbientLightSensor({frequency: 60});
ambientLightSensor.start();
let testPromise = sensor.mockSensorProvider.getCreatedSensor()
.then((mockSensor) => {
return new Promise((resolve, reject) => {
ambientLightSensor.onstatechange = event => {
if (ambientLightSensor.state === 'idle') {
resolve(mockSensor);
}
if (ambientLightSensor.state === 'active') {
ambientLightSensor.stop();
}
};
ambientLightSensor.onerror = reject;
});
})
.then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
return testPromise;
}, 'Test that sensor can be successfully created if sensor is supported.');
sensor_test(sensor => {
let ambientLightSensor = new AmbientLightSensor();
ambientLightSensor.start();
let testPromise = sensor.mockSensorProvider.getCreatedSensor()
.then((mockSensor) => {
return new Promise((resolve, reject) => {
ambientLightSensor.onstatechange = event => {
if (ambientLightSensor.state === 'idle') {
resolve(mockSensor);
}
if (ambientLightSensor.state === 'active') {
ambientLightSensor.stop();
}
};
ambientLightSensor.onerror = reject;
});
})
.then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
return testPromise;
}, 'Test that sensor can be constructed with default configuration.');
sensor_test(sensor => {
let ambientLightSensor = new AmbientLightSensor({frequency: 60});
ambientLightSensor.start();
let testPromise = sensor.mockSensorProvider.getCreatedSensor()
.then(mockSensor => { return mockSensor.addConfigurationCalled(); })
.then(mockSensor => {
return new Promise((resolve, reject) => {
ambientLightSensor.onstatechange = event => {
if (ambientLightSensor.state === 'idle') {
resolve(mockSensor);
}
if (ambientLightSensor.state === 'active') {
ambientLightSensor.stop();
}
};
});
})
.then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
return testPromise;
}, 'Test that addConfiguration and removeConfiguration is called.');
sensor_test(sensor => {
let ambientLightSensor = new AmbientLightSensor({frequency: 60});
ambientLightSensor.start();
let testPromise = sensor.mockSensorProvider.getCreatedSensor()
.then(mockSensor => {
return mockSensor.setUpdateSensorReadingFunction(update_sensor_reading);
})
.then((mockSensor) => {
return new Promise((resolve, reject) => {
ambientLightSensor.onstatechange = event => {
if (ambientLightSensor.state === 'idle') {
resolve(mockSensor);
}
};
ambientLightSensor.onchange = e => {
assert_equals(e.reading.illuminance, kDefaultReadingValue);
ambientLightSensor.stop();
};
ambientLightSensor.onerror = reject;
});
})
.then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
return testPromise;
}, 'Test that onChange is called and sensor reading is valid.');
sensor_test(sensor => {
let ambientLightSensor = new AmbientLightSensor({frequency: 60});
ambientLightSensor.start();
let testPromise = sensor.mockSensorProvider.getCreatedSensor()
.then(mockSensor => {
return mockSensor.setUpdateSensorReadingFunction(update_sensor_reading);
})
.then((mockSensor) => {
return new Promise((resolve, reject) => {
ambientLightSensor.onstatechange = () => {
if (ambientLightSensor.state === 'idle') {
assert_equals(ambientLightSensor.reading, null);
resolve(mockSensor);
}
}
ambientLightSensor.onchange = e => {
assert_equals(e.reading.illuminance, kDefaultReadingValue);
ambientLightSensor.stop();
}
ambientLightSensor.onerror = reject;
});
})
.then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
return testPromise;
}, 'Test that sensor reading is not updated when sensor is stopped.');
sensor_test(sensor => {
let ambientLightSensor = new AmbientLightSensor();
ambientLightSensor.start();
let testPromise = sensor.mockSensorProvider.getCreatedSensor()
.then(mockSensor => {
return mockSensor.setUpdateSensorReadingFunction(update_sensor_reading);
})
.then((mockSensor) => {
return new Promise((resolve, reject) => {
ambientLightSensor.onchange = e => {
if (e.reading.illuminance == kDefaultReadingValue) {
resolve(mockSensor);
}
}
ambientLightSensor.onerror = reject;
});
})
.then((mockSensor) => {
testRunner.setPageVisibility("hidden");
return mockSensor.suspendCalled();
})
.then((mockSensor) => {
testRunner.setPageVisibility("visible");
return mockSensor.resumeCalled();
})
.then((mockSensor) => {
return new Promise((resolve, reject) => {
ambientLightSensor.onstatechange = () => {
if (ambientLightSensor.state === 'idle') {
resolve(mockSensor);
}
}
ambientLightSensor.stop();
ambientLightSensor.onerror = reject;
});
})
.then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
return testPromise;
}, 'Test that sensor receives suspend / resume notifications when page'
+' visibility changes.');
</script>
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script>
test(function() {
// Test that AmbientLightSensor interface exists
assert_true(new AmbientLightSensor() instanceof AmbientLightSensor);
}, 'AmbientLightSensor IDL test');
</script>
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script>
test(function() {
// Test that AmbientLightSensorReading interface exists
assert_true(new AmbientLightSensorReading({illuminance: 1}) instanceof AmbientLightSensorReading);
}, 'AmbientLightSensorReading IDL test');
</script>
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="../resources/mojo-helpers.js"></script>
<script src="resources/sensor-helpers.js"></script>
<script>
'use strict';
sensor_test(sensor => {
assert_true(sensor instanceof Object);
assert_true(sensor.mockSensorProvider instanceof Object);
}, 'Sensor Mojo bindings and mock interfaces are available to tests.')
</script>
\ No newline at end of file
...@@ -17,6 +17,14 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE ...@@ -17,6 +17,14 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
[INTERFACES] [INTERFACES]
interface AmbientLightSensor : Sensor
attribute @@toStringTag
getter reading
method constructor
interface AmbientLightSensorReading : SensorReading
attribute @@toStringTag
getter illuminance
method constructor
interface AnalyserNode : AudioNode interface AnalyserNode : AudioNode
attribute @@toStringTag attribute @@toStringTag
getter fftSize getter fftSize
......
...@@ -216,6 +216,8 @@ modules_idl_files = ...@@ -216,6 +216,8 @@ modules_idl_files =
"remoteplayback/RemotePlayback.idl", "remoteplayback/RemotePlayback.idl",
"remoteplayback/RemotePlaybackAvailability.idl", "remoteplayback/RemotePlaybackAvailability.idl",
"screen_orientation/ScreenOrientation.idl", "screen_orientation/ScreenOrientation.idl",
"sensor/AmbientLightSensor.idl",
"sensor/AmbientLightSensorReading.idl",
"sensor/Sensor.idl", "sensor/Sensor.idl",
"sensor/SensorErrorEvent.idl", "sensor/SensorErrorEvent.idl",
"sensor/SensorReading.idl", "sensor/SensorReading.idl",
...@@ -445,6 +447,7 @@ modules_dictionary_idl_files = ...@@ -445,6 +447,7 @@ modules_dictionary_idl_files =
"push_messaging/PushEventInit.idl", "push_messaging/PushEventInit.idl",
"push_messaging/PushSubscriptionOptionsInit.idl", "push_messaging/PushSubscriptionOptionsInit.idl",
"quota/StorageEstimate.idl", "quota/StorageEstimate.idl",
"sensor/AmbientLightSensorReadingInit.idl",
"sensor/SensorErrorEventInit.idl", "sensor/SensorErrorEventInit.idl",
"sensor/SensorReadingEventInit.idl", "sensor/SensorReadingEventInit.idl",
"sensor/SensorOptions.idl", "sensor/SensorOptions.idl",
...@@ -769,6 +772,8 @@ generated_modules_dictionary_files = [ ...@@ -769,6 +772,8 @@ generated_modules_dictionary_files = [
"$blink_modules_output_dir/push_messaging/PushSubscriptionOptionsInit.h", "$blink_modules_output_dir/push_messaging/PushSubscriptionOptionsInit.h",
"$blink_modules_output_dir/quota/StorageEstimate.cpp", "$blink_modules_output_dir/quota/StorageEstimate.cpp",
"$blink_modules_output_dir/quota/StorageEstimate.h", "$blink_modules_output_dir/quota/StorageEstimate.h",
"$blink_modules_output_dir/sensor/AmbientLightSensorReadingInit.cpp",
"$blink_modules_output_dir/sensor/AmbientLightSensorReadingInit.h",
"$blink_modules_output_dir/sensor/SensorErrorEventInit.cpp", "$blink_modules_output_dir/sensor/SensorErrorEventInit.cpp",
"$blink_modules_output_dir/sensor/SensorErrorEventInit.h", "$blink_modules_output_dir/sensor/SensorErrorEventInit.h",
"$blink_modules_output_dir/sensor/SensorReadingEventInit.cpp", "$blink_modules_output_dir/sensor/SensorReadingEventInit.cpp",
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/sensor/AmbientLightSensor.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "modules/sensor/AmbientLightSensorReading.h"
using device::mojom::blink::SensorType;
namespace blink {
// static
AmbientLightSensor* AmbientLightSensor::create(ExecutionContext* context, const SensorOptions& sensorOptions)
{
return new AmbientLightSensor(context, sensorOptions);
}
// static
AmbientLightSensor* AmbientLightSensor::create(ExecutionContext* context)
{
return create(context, SensorOptions());
}
AmbientLightSensor::AmbientLightSensor(ExecutionContext* executionContext, const SensorOptions& sensorOptions)
: Sensor(executionContext, sensorOptions, SensorType::AMBIENT_LIGHT)
{
}
AmbientLightSensorReading* AmbientLightSensor::reading() const
{
return static_cast<AmbientLightSensorReading*>(Sensor::reading());
}
SensorReading* AmbientLightSensor::createSensorReading(SensorProxy* proxy)
{
return AmbientLightSensorReading::create(proxy);
}
auto AmbientLightSensor::createSensorConfig(const SensorOptions& options, const SensorConfiguration& defaultConfig) -> SensorConfigurationPtr
{
auto result = device::mojom::blink::SensorConfiguration::New();
result->frequency = options.hasFrequency() ? options.frequency() : defaultConfig.frequency;
return result;
}
DEFINE_TRACE(AmbientLightSensor)
{
Sensor::trace(visitor);
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef AmbientLightSensor_h
#define AmbientLightSensor_h
#include "modules/sensor/Sensor.h"
namespace blink {
class AmbientLightSensorReading;
class AmbientLightSensor final : public Sensor {
USING_GARBAGE_COLLECTED_MIXIN(AmbientLightSensor);
DEFINE_WRAPPERTYPEINFO();
public:
static AmbientLightSensor* create(ExecutionContext*, const SensorOptions&);
static AmbientLightSensor* create(ExecutionContext*);
AmbientLightSensorReading* reading() const;
DECLARE_VIRTUAL_TRACE();
private:
AmbientLightSensor(ExecutionContext*, const SensorOptions&);
// Sensor overrides.
SensorReading* createSensorReading(SensorProxy*) override;
SensorConfigurationPtr createSensorConfig(const SensorOptions&, const SensorConfiguration& defaultConfig) override;
};
} // namespace blink
#endif // AmbientLightSensor_h
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Specification at:
// https://w3c.github.io/ambient-light/#ambient-light-sensor-interface
[
RuntimeEnabled=Sensor,
Constructor(optional SensorOptions sensorOptions),
ConstructorCallWith=ExecutionContext,
] interface AmbientLightSensor : Sensor {
readonly attribute AmbientLightSensorReading? reading;
};
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/sensor/AmbientLightSensorReading.h"
#include "modules/sensor/SensorProxy.h"
namespace blink {
AmbientLightSensorReading::AmbientLightSensorReading(const AmbientLightSensorReadingInit& init)
: SensorReading(nullptr)
, mAmbientLightSensorReadingInit(init)
{
}
AmbientLightSensorReading::AmbientLightSensorReading(SensorProxy* proxy)
: SensorReading(proxy)
, mAmbientLightSensorReadingInit(AmbientLightSensorReadingInit())
{
}
AmbientLightSensorReading::~AmbientLightSensorReading() = default;
double AmbientLightSensorReading::illuminance() const
{
if (mAmbientLightSensorReadingInit.hasIlluminance())
return mAmbientLightSensorReadingInit.illuminance();
if (!m_sensorProxy)
return 0.0;
return m_sensorProxy->reading().reading[0];
}
bool AmbientLightSensorReading::isReadingUpdated(const SensorProxy::Reading& previous) const
{
if (!m_sensorProxy)
return false;
return previous.reading[0] != illuminance();
}
DEFINE_TRACE(AmbientLightSensorReading)
{
SensorReading::trace(visitor);
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef AmbientLightSensorReading_h
#define AmbientLightSensorReading_h
#include "modules/sensor/AmbientLightSensorReadingInit.h"
#include "modules/sensor/SensorReading.h"
namespace blink {
class AmbientLightSensorReading final
: public GarbageCollectedFinalized<AmbientLightSensorReading>
, public SensorReading {
USING_GARBAGE_COLLECTED_MIXIN(AmbientLightSensorReading);
DEFINE_WRAPPERTYPEINFO();
public:
static AmbientLightSensorReading* create(const AmbientLightSensorReadingInit& init)
{
return new AmbientLightSensorReading(init);
}
static AmbientLightSensorReading* create(SensorProxy* proxy)
{
return new AmbientLightSensorReading(proxy);
}
~AmbientLightSensorReading();
double illuminance() const;
bool isReadingUpdated(const SensorProxy::Reading&) const override;
DECLARE_VIRTUAL_TRACE();
private:
explicit AmbientLightSensorReading(const AmbientLightSensorReadingInit&);
explicit AmbientLightSensorReading(SensorProxy*);
private:
AmbientLightSensorReadingInit mAmbientLightSensorReadingInit;
};
} // namepsace blink
#endif // AmbientLightSensorReading_h
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Specification at:
// https://w3c.github.io/ambient-light/#ambient-light-sensor-reading-interface
[
RuntimeEnabled=Sensor,
Constructor(AmbientLightSensorReadingInit ambientLightSensorReadingInit)
] interface AmbientLightSensorReading : SensorReading {
readonly attribute unrestricted double illuminance;
};
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Specification at:
// https://w3c.github.io/ambient-light/#dictdef-ambientlightsensorreadinginit
dictionary AmbientLightSensorReadingInit {
unrestricted double illuminance;
};
...@@ -6,6 +6,10 @@ import("//third_party/WebKit/Source/modules/modules.gni") ...@@ -6,6 +6,10 @@ import("//third_party/WebKit/Source/modules/modules.gni")
blink_modules_sources("sensor") { blink_modules_sources("sensor") {
sources = [ sources = [
"AmbientLightSensor.cpp",
"AmbientLightSensor.h",
"AmbientLightSensorReading.cpp",
"AmbientLightSensorReading.h",
"Sensor.cpp", "Sensor.cpp",
"Sensor.h", "Sensor.h",
"SensorErrorEvent.cpp", "SensorErrorEvent.cpp",
......
...@@ -14,7 +14,6 @@ namespace blink { ...@@ -14,7 +14,6 @@ namespace blink {
SensorReading::SensorReading(SensorProxy* sensorProxy) SensorReading::SensorReading(SensorProxy* sensorProxy)
: m_sensorProxy(sensorProxy) : m_sensorProxy(sensorProxy)
{ {
DCHECK(m_sensorProxy);
} }
DEFINE_TRACE(SensorReading) DEFINE_TRACE(SensorReading)
...@@ -31,6 +30,15 @@ DOMHighResTimeStamp SensorReading::timeStamp(ScriptState* scriptState) const ...@@ -31,6 +30,15 @@ DOMHighResTimeStamp SensorReading::timeStamp(ScriptState* scriptState) const
Performance* performance = DOMWindowPerformance::performance(*window); Performance* performance = DOMWindowPerformance::performance(*window);
DCHECK(performance); DCHECK(performance);
if (!m_sensorProxy) {
// In cases when SensorReading derived classes are constructed from JS
// side, e.g. to create syntetic SensorReadingEvent for testing
// purposes, |m_sensorProxy| will be null and SensorReading.timeStamp
// would return current DOMHighResTimeStamp, while reading value should
// be provided by derived classes.
return performance->now();
}
return performance->monotonicTimeToDOMHighResTimeStamp(m_sensorProxy->reading().timestamp); return performance->monotonicTimeToDOMHighResTimeStamp(m_sensorProxy->reading().timestamp);
} }
......
...@@ -16,7 +16,7 @@ class ExecutionContext; ...@@ -16,7 +16,7 @@ class ExecutionContext;
class ScriptState; class ScriptState;
class SensorReading class SensorReading
: public GarbageCollected<SensorReading> : public GarbageCollectedMixin
, public ScriptWrappable { , public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment