Index: content/browser/device_orientation/data_fetcher_impl_win.cc |
diff --git a/content/browser/device_orientation/data_fetcher_impl_win.cc b/content/browser/device_orientation/data_fetcher_impl_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d08ed446ad623f4c8e577cc7fd97fdf01f14f559 |
--- /dev/null |
+++ b/content/browser/device_orientation/data_fetcher_impl_win.cc |
@@ -0,0 +1,193 @@ |
+// Copyright (c) 2013 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 "content/browser/device_orientation/data_fetcher_impl_win.h" |
+ |
+#include <InitGuid.h> |
+#include <PortableDeviceTypes.h> |
+#include <Sensors.h> |
+ |
+#include "base/logging.h" |
+#include "base/win/iunknown_impl.h" |
+#include "base/win/windows_version.h" |
+#include "content/browser/device_orientation/orientation.h" |
+ |
+namespace { |
+ |
+// This should match ProviderImpl::kDesiredSamplingIntervalMs. |
+const int kPeriodInMilliseconds = 100; |
+ |
+} // namespace |
+ |
+namespace content { |
+ |
+class DataFetcherImplWin::SensorEventSink : public ISensorEvents, |
+ public base::win::IUnknownImpl { |
+ public: |
+ explicit SensorEventSink(DataFetcherImplWin* const fetcher) |
+ : fetcher_(fetcher) {} |
+ |
+ virtual ~SensorEventSink() {} |
+ |
+ // IUnknown interface |
+ virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE { |
+ return IUnknownImpl::AddRef(); |
+ } |
+ |
+ virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE { |
+ return IUnknownImpl::Release(); |
+ } |
+ |
+ virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE { |
+ if (riid == __uuidof(ISensorEvents)) { |
+ *ppv = static_cast<ISensorEvents*>(this); |
+ AddRef(); |
+ return S_OK; |
+ } |
+ return IUnknownImpl::QueryInterface(riid, ppv); |
+ } |
+ |
+ // ISensorEvents interface |
+ STDMETHODIMP OnEvent(ISensor* sensor, |
+ REFGUID event_id, |
+ IPortableDeviceValues* event_data) OVERRIDE { |
+ return S_OK; |
+ } |
+ |
+ STDMETHODIMP OnDataUpdated(ISensor* sensor, |
+ ISensorDataReport* new_data) OVERRIDE { |
+ if (NULL == new_data || NULL == sensor) |
+ return E_INVALIDARG; |
+ |
+ PROPVARIANT value = {}; |
+ scoped_refptr<Orientation> orientation = new Orientation(); |
+ |
+ if (SUCCEEDED(new_data->GetSensorValue( |
+ SENSOR_DATA_TYPE_TILT_X_DEGREES, &value))) { |
+ orientation->set_beta(value.fltVal); |
+ } |
+ PropVariantClear(&value); |
+ |
+ if (SUCCEEDED(new_data->GetSensorValue( |
+ SENSOR_DATA_TYPE_TILT_Y_DEGREES, &value))) { |
+ orientation->set_gamma(value.fltVal); |
+ } |
+ PropVariantClear(&value); |
+ |
+ if (SUCCEEDED(new_data->GetSensorValue( |
+ SENSOR_DATA_TYPE_TILT_Z_DEGREES, &value))) { |
+ orientation->set_alpha(value.fltVal); |
+ } |
+ PropVariantClear(&value); |
+ |
+ orientation->set_absolute(true); |
+ fetcher_->OnOrientationData(orientation.get()); |
+ |
+ return S_OK; |
+ } |
+ |
+ STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) OVERRIDE { |
+ return S_OK; |
+ } |
+ |
+ STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) OVERRIDE { |
+ return S_OK; |
+ } |
+ |
+ private: |
+ DataFetcherImplWin* const fetcher_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SensorEventSink); |
+}; |
+ |
+// Create a DataFetcherImplWin object and return NULL if no valid sensor found. |
+// static |
+DataFetcher* DataFetcherImplWin::Create() { |
+ scoped_ptr<DataFetcherImplWin> fetcher(new DataFetcherImplWin); |
+ if (fetcher->Initialize()) |
+ return fetcher.release(); |
+ |
+ LOG(ERROR) << "DataFetcherImplWin::Initialize failed!"; |
+ return NULL; |
+} |
+ |
+DataFetcherImplWin::~DataFetcherImplWin() { |
+ if (sensor_) |
+ sensor_->SetEventSink(NULL); |
+} |
+ |
+DataFetcherImplWin::DataFetcherImplWin() { |
+} |
+ |
+void DataFetcherImplWin::OnOrientationData(Orientation* orientation) { |
+ // This method is called on Windows sensor thread. |
+ base::AutoLock autolock(next_orientation_lock_); |
+ next_orientation_ = orientation; |
+} |
+ |
+const DeviceData* DataFetcherImplWin::GetDeviceData(DeviceData::Type type) { |
+ if (type != DeviceData::kTypeOrientation) |
+ return NULL; |
+ return GetOrientation(); |
+} |
+ |
+const Orientation* DataFetcherImplWin::GetOrientation() { |
+ if (next_orientation_.get()) { |
+ base::AutoLock autolock(next_orientation_lock_); |
+ next_orientation_.swap(current_orientation_); |
+ } |
+ if (!current_orientation_.get()) |
+ return new Orientation(); |
+ return current_orientation_.get(); |
+} |
+ |
+bool DataFetcherImplWin::Initialize() { |
+ if (base::win::GetVersion() < base::win::VERSION_WIN7) |
+ return false; |
+ |
+ base::win::ScopedComPtr<ISensorManager> sensor_manager; |
+ HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager); |
+ if (FAILED(hr) || !sensor_manager) |
+ return false; |
+ |
+ base::win::ScopedComPtr<ISensorCollection> sensor_collection; |
+ hr = sensor_manager->GetSensorsByType( |
+ SENSOR_TYPE_INCLINOMETER_3D, sensor_collection.Receive()); |
+ |
+ if (FAILED(hr) || !sensor_collection) |
+ return false; |
+ |
+ ULONG count = 0; |
+ hr = sensor_collection->GetCount(&count); |
+ if (FAILED(hr) || !count) |
+ return false; |
+ |
+ hr = sensor_collection->GetAt(0, sensor_.Receive()); |
+ if (FAILED(hr) || !sensor_) |
+ return false; |
+ |
+ base::win::ScopedComPtr<IPortableDeviceValues> device_values; |
+ if (SUCCEEDED(device_values.CreateInstance(CLSID_PortableDeviceValues))) { |
+ if (SUCCEEDED(device_values->SetUnsignedIntegerValue( |
+ SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, kPeriodInMilliseconds))) { |
+ base::win::ScopedComPtr<IPortableDeviceValues> return_values; |
+ sensor_->SetProperties(device_values.get(), return_values.Receive()); |
+ } |
+ } |
+ |
+ scoped_refptr<SensorEventSink> sensor_event_impl(new SensorEventSink(this)); |
+ base::win::ScopedComPtr<ISensorEvents> sensor_events; |
+ hr = sensor_event_impl->QueryInterface( |
+ __uuidof(ISensorEvents), sensor_events.ReceiveVoid()); |
+ if (FAILED(hr) || !sensor_events) |
+ return false; |
+ |
+ hr = sensor_->SetEventSink(sensor_events); |
+ if (FAILED(hr)) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+} // namespace content |