// 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