Skip to content

Commit

Permalink
Use standardized and extendable accelerometer update type.
Browse files Browse the repository at this point in the history
Updates the type used when delivering accelerometer updates in ash to:
- support a variable number of accelerometers
- be measured in m/s^2
- use axes consistent with the web device motion API.

BUG=380831
TEST=MaximizeModeController unit tests still pass.
TEST=Run on a touchview device and verify that entering / exiting touchview as well as screen rotation still works.

Review URL: https://codereview.chromium.org/500613003

Cr-Commit-Position: refs/heads/master@{#292968}
  • Loading branch information
flackr authored and Commit bot committed Sep 2, 2014
1 parent 7cd720b commit 45f31ae
Show file tree
Hide file tree
Showing 20 changed files with 416 additions and 178 deletions.
2 changes: 2 additions & 0 deletions ash/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ component("ash") {
"//net",
"//skia",
"//third_party/icu",
"//ui/accelerometer",
"//ui/accessibility",
"//ui/app_list",
"//ui/aura",
Expand Down Expand Up @@ -251,6 +252,7 @@ test("ash_unittests") {
"//skia",
"//testing/gtest",
"//third_party/icu",
"//ui/accelerometer",
"//ui/accessibility",
"//ui/aura",
"//ui/aura:test_support",
Expand Down
8 changes: 3 additions & 5 deletions ash/accelerometer/accelerometer_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "ash/accelerometer/accelerometer_controller.h"

#include "ash/accelerometer/accelerometer_observer.h"
#include "ui/gfx/geometry/vector3d_f.h"

namespace ash {

Expand All @@ -31,11 +30,10 @@ void AccelerometerController::RemoveObserver(AccelerometerObserver* observer) {
}

#if defined(OS_CHROMEOS)
void AccelerometerController::HandleAccelerometerReading(
const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) {
void AccelerometerController::HandleAccelerometerUpdate(
const ui::AccelerometerUpdate& update) {
FOR_EACH_OBSERVER(AccelerometerObserver, observers_,
OnAccelerometerUpdated(base, lid));
OnAccelerometerUpdated(update));
}
#endif

Expand Down
8 changes: 2 additions & 6 deletions ash/accelerometer/accelerometer_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ namespace base {
class TaskRunner;
}

namespace gfx {
class Vector3dF;
}

namespace ash {

class AccelerometerObserver;
Expand Down Expand Up @@ -50,8 +46,8 @@ class ASH_EXPORT AccelerometerController
// This needs to be CHROMEOS only as on other platforms it does not actually
// override a method.
// chromeos::AccelerometerReader::Delegate:
virtual void HandleAccelerometerReading(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) OVERRIDE;
virtual void HandleAccelerometerUpdate(
const ui::AccelerometerUpdate& update) OVERRIDE;
#endif

private:
Expand Down
13 changes: 5 additions & 8 deletions ash/accelerometer/accelerometer_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,17 @@
#define ASH_ACCELEROMETER_ACCELEROMETER_OBSERVER_H_

#include "ash/ash_export.h"

namespace gfx {
class Vector3dF;
}
#include "ui/accelerometer/accelerometer_types.h"

namespace ash {

// The interface for classes which observe accelerometer updates.
class ASH_EXPORT AccelerometerObserver {
public:
// Invoked when an accelerometer reading has been taken. The |base| and |lid|
// accelerometer readings are in G's.
virtual void OnAccelerometerUpdated(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) = 0;
// Invoked when an accelerometer reading has been taken. The |update| can
// contain readings from one or more AccelerometerSources.
virtual void OnAccelerometerUpdated(
const ui::AccelerometerUpdate& update) = 0;

protected:
virtual ~AccelerometerObserver() {}
Expand Down
2 changes: 2 additions & 0 deletions ash/ash.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,7 @@
'../skia/skia.gyp:skia',
'../third_party/icu/icu.gyp:icui18n',
'../third_party/icu/icu.gyp:icuuc',
'../ui/accelerometer/ui_accelerometer.gyp:ui_accelerometer',
'../ui/accessibility/accessibility.gyp:accessibility',
'../ui/app_list/app_list.gyp:app_list',
'../ui/aura/aura.gyp:aura',
Expand Down Expand Up @@ -1065,6 +1066,7 @@
'../testing/gtest.gyp:gtest',
'../third_party/icu/icu.gyp:icui18n',
'../third_party/icu/icu.gyp:icuuc',
'../ui/accelerometer/ui_accelerometer.gyp:ui_accelerometer',
'../ui/accessibility/accessibility.gyp:accessibility',
'../ui/app_list/app_list.gyp:app_list',
'../ui/aura/aura.gyp:aura',
Expand Down
95 changes: 55 additions & 40 deletions ash/wm/maximize_mode/maximize_mode_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,34 +56,37 @@ const float kMaxStableAngle = 340.0f;
const base::TimeDelta kLidRecentlyOpenedDuration =
base::TimeDelta::FromSeconds(2);

// The mean acceleration due to gravity on Earth in m/s^2.
const float kMeanGravity = 9.80665f;

// When the device approaches vertical orientation (i.e. portrait orientation)
// the accelerometers for the base and lid approach the same values (i.e.
// gravity pointing in the direction of the hinge). When this happens we cannot
// compute the hinge angle reliably and must turn ignore accelerometer readings.
// This is the minimum acceleration perpendicular to the hinge under which to
// detect hinge angle.
const float kHingeAngleDetectionThreshold = 0.25f;
// detect hinge angle in m/s^2.
const float kHingeAngleDetectionThreshold = 2.5f;

// The maximum deviation from the acceleration expected due to gravity under
// which to detect hinge angle and screen rotation.
const float kDeviationFromGravityThreshold = 0.1f;
// which to detect hinge angle and screen rotation in m/s^2
const float kDeviationFromGravityThreshold = 1.0f;

// The maximum deviation between the magnitude of the two accelerometers under
// which to detect hinge angle and screen rotation. These accelerometers are
// attached to the same physical device and so should be under the same
// acceleration.
const float kNoisyMagnitudeDeviation = 0.1f;
// which to detect hinge angle and screen rotation in m/s^2. These
// accelerometers are attached to the same physical device and so should be
// under the same acceleration.
const float kNoisyMagnitudeDeviation = 1.0f;

// The angle which the screen has to be rotated past before the display will
// rotate to match it (i.e. 45.0f is no stickiness).
const float kDisplayRotationStickyAngleDegrees = 60.0f;

// The minimum acceleration in a direction required to trigger screen rotation.
// This prevents rapid toggling of rotation when the device is near flat and
// there is very little screen aligned force on it. The value is effectively the
// sine of the rise angle required, with the current value requiring at least a
// 25 degree rise.
const float kMinimumAccelerationScreenRotation = 0.42f;
// The minimum acceleration in m/s^2 in a direction required to trigger screen
// rotation. This prevents rapid toggling of rotation when the device is near
// flat and there is very little screen aligned force on it. The value is
// effectively the sine of the rise angle required times the acceleration due
// to gravity, with the current value requiring at least a 25 degree rise.
const float kMinimumAccelerationScreenRotation = 4.2f;

const float kRadiansToDegrees = 180.0f / 3.14159265f;

Expand Down Expand Up @@ -236,26 +239,35 @@ void MaximizeModeController::Shutdown() {
}

void MaximizeModeController::OnAccelerometerUpdated(
const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) {
const ui::AccelerometerUpdate& update) {
bool first_accelerometer_update = !have_seen_accelerometer_data_;
have_seen_accelerometer_data_ = true;

// Ignore the reading if it appears unstable. The reading is considered
// unstable if it deviates too much from gravity and/or the magnitude of the
// reading from the lid differs too much from the reading from the base.
float base_magnitude = base.Length();
float lid_magnitude = lid.Length();
if (std::abs(base_magnitude - lid_magnitude) > kNoisyMagnitudeDeviation ||
std::abs(base_magnitude - 1.0f) > kDeviationFromGravityThreshold ||
std::abs(lid_magnitude - 1.0f) > kDeviationFromGravityThreshold) {
return;
float base_magnitude =
update.has(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) ?
update.get(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD).Length() :
0.0f;
float lid_magnitude = update.has(ui::ACCELEROMETER_SOURCE_SCREEN) ?
update.get(ui::ACCELEROMETER_SOURCE_SCREEN).Length() : 0.0f;
bool lid_stable = update.has(ui::ACCELEROMETER_SOURCE_SCREEN) &&
std::abs(lid_magnitude - kMeanGravity) <= kDeviationFromGravityThreshold;
bool base_angle_stable = lid_stable &&
update.has(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) &&
std::abs(base_magnitude - lid_magnitude) <= kNoisyMagnitudeDeviation &&
std::abs(base_magnitude - kMeanGravity) <= kDeviationFromGravityThreshold;

if (base_angle_stable) {
// Responding to the hinge rotation can change the maximize mode state which
// affects screen rotation, so we handle hinge rotation first.
HandleHingeRotation(
update.get(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD),
update.get(ui::ACCELEROMETER_SOURCE_SCREEN));
}

// Responding to the hinge rotation can change the maximize mode state which
// affects screen rotation, so we handle hinge rotation first.
HandleHingeRotation(base, lid);
HandleScreenRotation(lid);
if (lid_stable)
HandleScreenRotation(update.get(ui::ACCELEROMETER_SOURCE_SCREEN));

if (first_accelerometer_update) {
// On the first accelerometer update we will know if we have entered
Expand Down Expand Up @@ -303,14 +315,14 @@ void MaximizeModeController::SuspendDone(

void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) {
static const gfx::Vector3dF hinge_vector(0.0f, 1.0f, 0.0f);
static const gfx::Vector3dF hinge_vector(1.0f, 0.0f, 0.0f);
bool maximize_mode_engaged = IsMaximizeModeWindowManagerEnabled();
// Ignore the component of acceleration parallel to the hinge for the purposes
// of hinge angle calculation.
gfx::Vector3dF base_flattened(base);
gfx::Vector3dF lid_flattened(lid);
base_flattened.set_y(0.0f);
lid_flattened.set_y(0.0f);
base_flattened.set_x(0.0f);
lid_flattened.set_x(0.0f);

// As the hinge approaches a vertical angle, the base and lid accelerometers
// approach the same values making any angle calculations highly inaccurate.
Expand All @@ -321,10 +333,13 @@ void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base,
}

// Compute the angle between the base and the lid.
float angle = ClockwiseAngleBetweenVectorsInDegrees(base_flattened,
lid_flattened, hinge_vector);
float lid_angle = 180.0f - ClockwiseAngleBetweenVectorsInDegrees(
base_flattened, lid_flattened, hinge_vector);
if (lid_angle < 0.0f)
lid_angle += 360.0f;

bool is_angle_stable = angle > kMinStableAngle && angle < kMaxStableAngle;
bool is_angle_stable = lid_angle >= kMinStableAngle &&
lid_angle <= kMaxStableAngle;

// Clear the last_lid_open_time_ for a stable reading so that there is less
// chance of a delay if the lid is moved from the close state to the fully
Expand All @@ -337,10 +352,10 @@ void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base,
// such that observations of state changes occur after the change and shell
// has fewer states to track.
if (maximize_mode_engaged && is_angle_stable &&
angle < kExitMaximizeModeAngle) {
lid_angle <= kExitMaximizeModeAngle) {
LeaveMaximizeMode();
} else if (!lid_is_closed_ && !maximize_mode_engaged &&
angle > kEnterMaximizeModeAngle &&
lid_angle >= kEnterMaximizeModeAngle &&
(is_angle_stable || !WasLidOpenedRecently())) {
EnterMaximizeMode();
}
Expand Down Expand Up @@ -372,21 +387,21 @@ void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) {
// The reference vector is the angle of gravity when the device is rotated
// clockwise by 45 degrees. Computing the angle between this vector and
// gravity we can easily determine the expected display rotation.
static gfx::Vector3dF rotation_reference(-1.0f, 1.0f, 0.0f);
static const gfx::Vector3dF rotation_reference(-1.0f, -1.0f, 0.0f);

// Set the down vector to match the expected direction of gravity given the
// last configured rotation. This is used to enforce a stickiness that the
// user must overcome to rotate the display and prevents frequent rotations
// when holding the device near 45 degrees.
gfx::Vector3dF down(0.0f, 0.0f, 0.0f);
if (current_rotation == gfx::Display::ROTATE_0)
down.set_x(-1.0f);
down.set_y(-1.0f);
else if (current_rotation == gfx::Display::ROTATE_90)
down.set_y(1.0f);
down.set_x(-1.0f);
else if (current_rotation == gfx::Display::ROTATE_180)
down.set_x(1.0f);
down.set_y(1.0f);
else
down.set_y(-1.0f);
down.set_x(1.0f);

// Don't rotate if the screen has not passed the threshold.
if (AngleBetweenVectorsInDegrees(down, lid_flattened) <
Expand Down
4 changes: 2 additions & 2 deletions ash/wm/maximize_mode/maximize_mode_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ class ASH_EXPORT MaximizeModeController
void Shutdown();

// AccelerometerObserver:
virtual void OnAccelerometerUpdated(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) OVERRIDE;
virtual void OnAccelerometerUpdated(
const ui::AccelerometerUpdate& update) OVERRIDE;

// ShellObserver:
virtual void OnAppTerminating() OVERRIDE;
Expand Down
Loading

0 comments on commit 45f31ae

Please sign in to comment.