| Index: athena/system/orientation_controller.cc
|
| diff --git a/athena/system/orientation_controller.cc b/athena/system/orientation_controller.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..06a4b521650c4f13d7e036c60f4e8b0c2f6139f9
|
| --- /dev/null
|
| +++ b/athena/system/orientation_controller.cc
|
| @@ -0,0 +1,129 @@
|
| +// Copyright 2014 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 "athena/screen/public/screen_manager.h"
|
| +#include "athena/system/orientation_controller.h"
|
| +#include "base/file_util.h"
|
| +#include "base/files/file_path_watcher.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +
|
| +namespace athena {
|
| +
|
| +namespace {
|
| +
|
| +// Path of the socket which the sensor daemon creates.
|
| +const char kSocketPath[] = "/dev/sensors/orientation";
|
| +
|
| +// Threshold after which to rotate in a given direction.
|
| +const int kGravityThreshold = 6.0f;
|
| +
|
| +// Minimum delay before triggering another orientation change.
|
| +const int kOrientationChangeDelayNS = 500000000;
|
| +
|
| +enum {
|
| + SENSOR_ACCELEROMETER,
|
| + SENSOR_LIGHT,
|
| + SENSOR_PROXIMITY
|
| +};
|
| +
|
| +// A sensor event from the device.
|
| +struct DeviceSensorEvent {
|
| + // The type of event from the enum above.
|
| + int32_t type;
|
| +
|
| + // The time in nanoseconds at which the event happened.
|
| + int64_t timestamp;
|
| +
|
| + union {
|
| + // Accelerometer X,Y,Z values in SI units (m/s^2) including gravity.
|
| + // The orientation is described at
|
| + // http://www.html5rocks.com/en/tutorials/device/orientation/.
|
| + float data[3];
|
| +
|
| + // Ambient (room) temperature in degrees Celcius.
|
| + float temperature;
|
| +
|
| + // Proximity sensor distance in centimeters.
|
| + float distance;
|
| +
|
| + // Ambient light level in SI lux units.
|
| + float light;
|
| + };
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +OrientationController::OrientationController()
|
| + : DeviceSocketListener(kSocketPath, sizeof(DeviceSensorEvent)),
|
| + last_orientation_change_time_(0),
|
| + weak_factory_(this) {
|
| + base::FilePath socket_path(kSocketPath);
|
| + if (base::PathExists(socket_path)) {
|
| + StartListening();
|
| + } else {
|
| + // Watch for socket to be created if it doesn't already exist.
|
| + watcher_.reset(new base::FilePathWatcher);
|
| + watcher_->Watch(socket_path, false,
|
| + base::Bind(&OrientationController::OnFilePathChanged,
|
| + weak_factory_.GetWeakPtr()));
|
| + }
|
| +}
|
| +
|
| +OrientationController::~OrientationController() {
|
| +}
|
| +
|
| +void OrientationController::OnDataAvailableOnIO(const void* data) {
|
| + const DeviceSensorEvent* event =
|
| + static_cast<const DeviceSensorEvent*>(data);
|
| + if (event->type != SENSOR_ACCELEROMETER)
|
| + return;
|
| +
|
| + float gravity_x = event->data[0];
|
| + float gravity_y = event->data[1];
|
| + gfx::Display::Rotation rotation;
|
| + if (gravity_x < -kGravityThreshold) {
|
| + rotation = gfx::Display::ROTATE_270;
|
| + } else if (gravity_x > kGravityThreshold) {
|
| + rotation = gfx::Display::ROTATE_90;
|
| + } else if (gravity_y < -kGravityThreshold) {
|
| + rotation = gfx::Display::ROTATE_180;
|
| + } else if (gravity_y > kGravityThreshold) {
|
| + rotation = gfx::Display::ROTATE_0;
|
| + } else {
|
| + // No rotation as gravity threshold was not hit.
|
| + return;
|
| + }
|
| +
|
| + if (rotation == current_rotation_ ||
|
| + event->timestamp - last_orientation_change_time_ <
|
| + kOrientationChangeDelayNS) {
|
| + return;
|
| + }
|
| +
|
| + last_orientation_change_time_ = event->timestamp;
|
| + current_rotation_ = rotation;
|
| +
|
| + // TODO(flackr): Avoid callbacks using unretained pointers. This could
|
| + // technically call RotateOnUI after OrientationController has destructed. We
|
| + // should instead use callbacks with weak pointers similar to
|
| + // chromeos/accelerometer/accelerometer_reader.cc.
|
| + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&OrientationController::RotateOnUI,
|
| + base::Unretained(this), rotation));
|
| +}
|
| +
|
| +void OrientationController::RotateOnUI(gfx::Display::Rotation rotation) {
|
| + ScreenManager::Get()->SetRotation(rotation);
|
| +}
|
| +
|
| +void OrientationController::OnFilePathChanged(const base::FilePath& path,
|
| + bool error) {
|
| + if (error)
|
| + return;
|
| +
|
| + StartListening();
|
| + watcher_.reset();
|
| +}
|
| +
|
| +} // namespace athena
|
|
|