1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/device_orientation/data_fetcher_impl_win.h" 6 7#include <InitGuid.h> 8#include <PortableDeviceTypes.h> 9#include <Sensors.h> 10 11#include "base/logging.h" 12#include "base/win/iunknown_impl.h" 13#include "base/win/windows_version.h" 14#include "content/browser/device_orientation/orientation.h" 15 16namespace { 17 18// This should match ProviderImpl::kDesiredSamplingIntervalMs. 19const int kPeriodInMilliseconds = 100; 20 21} // namespace 22 23namespace content { 24 25class DataFetcherImplWin::SensorEventSink : public ISensorEvents, 26 public base::win::IUnknownImpl { 27 public: 28 explicit SensorEventSink(DataFetcherImplWin* const fetcher) 29 : fetcher_(fetcher) {} 30 31 virtual ~SensorEventSink() {} 32 33 // IUnknown interface 34 virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE { 35 return IUnknownImpl::AddRef(); 36 } 37 38 virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE { 39 return IUnknownImpl::Release(); 40 } 41 42 virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE { 43 if (riid == __uuidof(ISensorEvents)) { 44 *ppv = static_cast<ISensorEvents*>(this); 45 AddRef(); 46 return S_OK; 47 } 48 return IUnknownImpl::QueryInterface(riid, ppv); 49 } 50 51 // ISensorEvents interface 52 STDMETHODIMP OnEvent(ISensor* sensor, 53 REFGUID event_id, 54 IPortableDeviceValues* event_data) OVERRIDE { 55 return S_OK; 56 } 57 58 STDMETHODIMP OnDataUpdated(ISensor* sensor, 59 ISensorDataReport* new_data) OVERRIDE { 60 if (NULL == new_data || NULL == sensor) 61 return E_INVALIDARG; 62 63 PROPVARIANT value = {}; 64 scoped_refptr<Orientation> orientation = new Orientation(); 65 66 if (SUCCEEDED(new_data->GetSensorValue( 67 SENSOR_DATA_TYPE_TILT_X_DEGREES, &value))) { 68 orientation->set_beta(value.fltVal); 69 } 70 PropVariantClear(&value); 71 72 if (SUCCEEDED(new_data->GetSensorValue( 73 SENSOR_DATA_TYPE_TILT_Y_DEGREES, &value))) { 74 orientation->set_gamma(value.fltVal); 75 } 76 PropVariantClear(&value); 77 78 if (SUCCEEDED(new_data->GetSensorValue( 79 SENSOR_DATA_TYPE_TILT_Z_DEGREES, &value))) { 80 orientation->set_alpha(value.fltVal); 81 } 82 PropVariantClear(&value); 83 84 orientation->set_absolute(true); 85 fetcher_->OnOrientationData(orientation.get()); 86 87 return S_OK; 88 } 89 90 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) OVERRIDE { 91 return S_OK; 92 } 93 94 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) OVERRIDE { 95 return S_OK; 96 } 97 98 private: 99 DataFetcherImplWin* const fetcher_; 100 101 DISALLOW_COPY_AND_ASSIGN(SensorEventSink); 102}; 103 104// Create a DataFetcherImplWin object and return NULL if no valid sensor found. 105// static 106DataFetcher* DataFetcherImplWin::Create() { 107 scoped_ptr<DataFetcherImplWin> fetcher(new DataFetcherImplWin); 108 if (fetcher->Initialize()) 109 return fetcher.release(); 110 111 LOG(ERROR) << "DataFetcherImplWin::Initialize failed!"; 112 return NULL; 113} 114 115DataFetcherImplWin::~DataFetcherImplWin() { 116 if (sensor_) 117 sensor_->SetEventSink(NULL); 118} 119 120DataFetcherImplWin::DataFetcherImplWin() { 121} 122 123void DataFetcherImplWin::OnOrientationData(Orientation* orientation) { 124 // This method is called on Windows sensor thread. 125 base::AutoLock autolock(next_orientation_lock_); 126 next_orientation_ = orientation; 127} 128 129const DeviceData* DataFetcherImplWin::GetDeviceData(DeviceData::Type type) { 130 if (type != DeviceData::kTypeOrientation) 131 return NULL; 132 return GetOrientation(); 133} 134 135const Orientation* DataFetcherImplWin::GetOrientation() { 136 if (next_orientation_.get()) { 137 base::AutoLock autolock(next_orientation_lock_); 138 next_orientation_.swap(current_orientation_); 139 } 140 if (!current_orientation_.get()) 141 return new Orientation(); 142 return current_orientation_.get(); 143} 144 145bool DataFetcherImplWin::Initialize() { 146 if (base::win::GetVersion() < base::win::VERSION_WIN7) 147 return false; 148 149 base::win::ScopedComPtr<ISensorManager> sensor_manager; 150 HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager); 151 if (FAILED(hr) || !sensor_manager) 152 return false; 153 154 base::win::ScopedComPtr<ISensorCollection> sensor_collection; 155 hr = sensor_manager->GetSensorsByType( 156 SENSOR_TYPE_INCLINOMETER_3D, sensor_collection.Receive()); 157 158 if (FAILED(hr) || !sensor_collection) 159 return false; 160 161 ULONG count = 0; 162 hr = sensor_collection->GetCount(&count); 163 if (FAILED(hr) || !count) 164 return false; 165 166 hr = sensor_collection->GetAt(0, sensor_.Receive()); 167 if (FAILED(hr) || !sensor_) 168 return false; 169 170 base::win::ScopedComPtr<IPortableDeviceValues> device_values; 171 if (SUCCEEDED(device_values.CreateInstance(CLSID_PortableDeviceValues))) { 172 if (SUCCEEDED(device_values->SetUnsignedIntegerValue( 173 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, kPeriodInMilliseconds))) { 174 base::win::ScopedComPtr<IPortableDeviceValues> return_values; 175 sensor_->SetProperties(device_values.get(), return_values.Receive()); 176 } 177 } 178 179 scoped_refptr<SensorEventSink> sensor_event_impl(new SensorEventSink(this)); 180 base::win::ScopedComPtr<ISensorEvents> sensor_events; 181 hr = sensor_event_impl->QueryInterface( 182 __uuidof(ISensorEvents), sensor_events.ReceiveVoid()); 183 if (FAILED(hr) || !sensor_events) 184 return false; 185 186 hr = sensor_->SetEventSink(sensor_events); 187 if (FAILED(hr)) 188 return false; 189 190 return true; 191} 192 193} // namespace content 194