Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ash/wm/maximize_mode/maximize_mode_controller.h" | 5 #include "ash/wm/maximize_mode/maximize_mode_controller.h" |
| 6 | 6 |
| 7 #include "ash/accelerometer/accelerometer_controller.h" | 7 #include "ash/accelerometer/accelerometer_controller.h" |
| 8 #include "ash/display/display_manager.h" | |
| 8 #include "ash/shell.h" | 9 #include "ash/shell.h" |
| 9 #include "ui/gfx/vector3d_f.h" | 10 #include "ui/gfx/vector3d_f.h" |
| 10 | 11 |
| 11 namespace ash { | 12 namespace ash { |
| 12 | 13 |
| 13 namespace { | 14 namespace { |
| 14 | 15 |
| 15 // The hinge angle at which to enter maximize mode. | 16 // The hinge angle at which to enter maximize mode. |
| 16 const float kEnterMaximizeModeAngle = 200.0f; | 17 const float kEnterMaximizeModeAngle = 200.0f; |
| 17 | 18 |
| 18 // The angle at which to exit maximize mode, this is specifically less than the | 19 // The angle at which to exit maximize mode, this is specifically less than the |
| 19 // angle to enter maximize mode to prevent rapid toggling when near the angle. | 20 // angle to enter maximize mode to prevent rapid toggling when near the angle. |
| 20 const float kExitMaximizeModeAngle = 160.0f; | 21 const float kExitMaximizeModeAngle = 160.0f; |
| 21 | 22 |
| 22 // When the lid is fully open 360 degrees, the accelerometer readings can | 23 // When the lid is fully open 360 degrees, the accelerometer readings can |
| 23 // occasionally appear as though the lid is almost closed. If the lid appears | 24 // occasionally appear as though the lid is almost closed. If the lid appears |
| 24 // near closed but the device is on we assume it is an erroneous reading from | 25 // near closed but the device is on we assume it is an erroneous reading from |
| 25 // it being open 360 degrees. | 26 // it being open 360 degrees. |
| 26 const float kFullyOpenAngleErrorTolerance = 10.0f; | 27 const float kFullyOpenAngleErrorTolerance = 10.0f; |
| 27 | 28 |
| 28 // When the device approaches vertical orientation (i.e. portrait orientation) | 29 // When the device approaches vertical orientation (i.e. portrait orientation) |
| 29 // the accelerometers for the base and lid approach the same values (i.e. | 30 // the accelerometers for the base and lid approach the same values (i.e. |
| 30 // gravity pointing in the direction of the hinge). When this happens we cannot | 31 // gravity pointing in the direction of the hinge). When this happens we cannot |
| 31 // compute the hinge angle reliably and must turn ignore accelerometer readings. | 32 // compute the hinge angle reliably and must turn ignore accelerometer readings. |
| 32 // This is the angle from vertical under which we will not compute a hinge | 33 // This is the angle from vertical under which we will not compute a hinge |
| 33 // angle. | 34 // angle. |
| 34 const float kHingeAxisAlignedThreshold = 15.0f; | 35 const float kHingeAxisAlignedThreshold = 15.0f; |
| 35 | 36 |
| 37 // The angle which the screen has to be rotated past before the display will | |
| 38 // rotate to match it (i.e. 45.0f is no stickiness). | |
| 39 const float kDisplayRotationStickyAngleDegrees = 60.0f; | |
| 40 | |
| 41 // The minimum acceleration in a direction required to trigger screen rotation. | |
| 42 // This prevents rapid toggling of rotation when the device is near flat and | |
| 43 // there is very little screen aligned force on it. | |
| 44 const float kMinimumAccelerationScreenRotation = 0.3f; | |
| 45 | |
| 36 const float kRadiansToDegrees = 180.0f / 3.14159265f; | 46 const float kRadiansToDegrees = 180.0f / 3.14159265f; |
| 37 | 47 |
| 38 // Returns the angle between |base| and |other| in degrees. | 48 // Returns the angle between |base| and |other| in degrees. |
| 39 float AngleBetweenVectorsInDegrees(const gfx::Vector3dF& base, | 49 float AngleBetweenVectorsInDegrees(const gfx::Vector3dF& base, |
| 40 const gfx::Vector3dF& other) { | 50 const gfx::Vector3dF& other) { |
| 41 return acos(gfx::DotProduct(base, other) / | 51 return acos(gfx::DotProduct(base, other) / |
| 42 base.Length() / other.Length()) * kRadiansToDegrees; | 52 base.Length() / other.Length()) * kRadiansToDegrees; |
| 43 } | 53 } |
| 44 | 54 |
| 45 // Returns the clockwise angle between |base| and |other| where |normal| is the | 55 // Returns the clockwise angle between |base| and |other| where |normal| is the |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 64 Shell::GetInstance()->accelerometer_controller()->AddObserver(this); | 74 Shell::GetInstance()->accelerometer_controller()->AddObserver(this); |
| 65 } | 75 } |
| 66 | 76 |
| 67 MaximizeModeController::~MaximizeModeController() { | 77 MaximizeModeController::~MaximizeModeController() { |
| 68 Shell::GetInstance()->accelerometer_controller()->RemoveObserver(this); | 78 Shell::GetInstance()->accelerometer_controller()->RemoveObserver(this); |
| 69 } | 79 } |
| 70 | 80 |
| 71 void MaximizeModeController::OnAccelerometerUpdated( | 81 void MaximizeModeController::OnAccelerometerUpdated( |
| 72 const gfx::Vector3dF& base, | 82 const gfx::Vector3dF& base, |
| 73 const gfx::Vector3dF& lid) { | 83 const gfx::Vector3dF& lid) { |
| 84 // Responding to the hinge rotation can change the maximize mode state which | |
| 85 // affects screen rotation, so we handle hinge rotation first. | |
| 86 HandleHingeRotation(base, lid); | |
| 87 HandleScreenRotation(lid); | |
| 88 } | |
| 89 | |
| 90 void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base, | |
| 91 const gfx::Vector3dF& lid) { | |
| 74 static const gfx::Vector3dF hinge_vector(0.0f, 1.0f, 0.0f); | 92 static const gfx::Vector3dF hinge_vector(0.0f, 1.0f, 0.0f); |
| 93 bool maximize_mode_engaged = | |
| 94 Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled(); | |
| 75 | 95 |
| 76 // As the hinge approaches a vertical angle, the base and lid accelerometers | 96 // As the hinge approaches a vertical angle, the base and lid accelerometers |
| 77 // approach the same values making any angle calculations highly inaccurate. | 97 // approach the same values making any angle calculations highly inaccurate. |
| 78 // Bail out early when it is too close. | 98 // Bail out early when it is too close. |
| 79 float hinge_angle = AngleBetweenVectorsInDegrees(base, hinge_vector); | 99 float hinge_angle = AngleBetweenVectorsInDegrees(base, hinge_vector); |
| 80 if (hinge_angle < kHingeAxisAlignedThreshold || | 100 if (hinge_angle < kHingeAxisAlignedThreshold || |
| 81 hinge_angle > 180.0f - kHingeAxisAlignedThreshold) | 101 hinge_angle > 180.0f - kHingeAxisAlignedThreshold) { |
| 82 return; | 102 return; |
| 103 } | |
| 83 | 104 |
| 84 // Compute the angle between the base and the lid. | 105 // Compute the angle between the base and the lid. |
| 85 float angle = ClockwiseAngleBetweenVectorsInDegrees(base, lid, hinge_vector); | 106 float angle = ClockwiseAngleBetweenVectorsInDegrees(base, lid, hinge_vector); |
| 86 | 107 |
| 87 // Toggle maximize mode on or off when corresponding thresholds are passed. | 108 // Toggle maximize mode on or off when corresponding thresholds are passed. |
| 88 // TODO(flackr): Make MaximizeModeController own the MaximizeModeWindowManager | 109 // TODO(flackr): Make MaximizeModeController own the MaximizeModeWindowManager |
| 89 // such that observations of state changes occur after the change and shell | 110 // such that observations of state changes occur after the change and shell |
| 90 // has fewer states to track. | 111 // has fewer states to track. |
| 91 bool maximize_mode_engaged = | |
| 92 Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled(); | |
| 93 if (maximize_mode_engaged && | 112 if (maximize_mode_engaged && |
| 94 angle > kFullyOpenAngleErrorTolerance && | 113 angle > kFullyOpenAngleErrorTolerance && |
| 95 angle < kExitMaximizeModeAngle) { | 114 angle < kExitMaximizeModeAngle) { |
| 96 Shell::GetInstance()->EnableMaximizeModeWindowManager(false); | 115 Shell::GetInstance()->EnableMaximizeModeWindowManager(false); |
| 97 } else if (!maximize_mode_engaged && | 116 } else if (!maximize_mode_engaged && |
| 98 angle > kEnterMaximizeModeAngle) { | 117 angle > kEnterMaximizeModeAngle) { |
| 99 Shell::GetInstance()->EnableMaximizeModeWindowManager(true); | 118 Shell::GetInstance()->EnableMaximizeModeWindowManager(true); |
| 100 } | 119 } |
| 101 } | 120 } |
| 102 | 121 |
| 122 void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) { | |
| 123 bool maximize_mode_engaged = | |
| 124 Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled(); | |
| 125 | |
| 126 internal::DisplayManager* display_manager = | |
| 127 Shell::GetInstance()->display_manager(); | |
| 128 gfx::Display::Rotation current_rotation = display_manager->GetDisplayInfo( | |
| 129 gfx::Display::InternalDisplayId()).rotation(); | |
| 130 | |
| 131 // If maximize mode is not engaged, ensure the screen is not rotated and | |
| 132 // do not rotate to match the current device orientation. | |
| 133 if (!maximize_mode_engaged) { | |
| 134 if (current_rotation != gfx::Display::ROTATE_0) { | |
| 135 // TODO(flackr): Currently this will prevent setting a manual rotation on | |
| 136 // the screen of a device with an accelerometer, this should only set it | |
| 137 // back to ROTATE_0 if it was last set by the accelerometer. | |
|
oshima
2014/04/03 19:19:49
SetDisplayRotation will save the setting to the lo
flackr
2014/04/03 19:43:46
Done.
| |
| 138 display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(), | |
| 139 gfx::Display::ROTATE_0); | |
| 140 } | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 // After determining maximize mode state, determine if the screen should | |
| 145 // be rotated. | |
| 146 gfx::Vector3dF lid_flattened(lid.x(), lid.y(), 0.0f); | |
| 147 float lid_flattened_length = lid_flattened.Length(); | |
| 148 // When the lid is close to being flat, don't change rotation as it is too | |
| 149 // sensitive to slight movements. | |
| 150 if (lid_flattened_length < kMinimumAccelerationScreenRotation) | |
| 151 return; | |
| 152 | |
| 153 // The reference vector is the angle of gravity when the device is rotated | |
| 154 // clockwise by 45 degrees. Computing the angle between this vector and | |
| 155 // gravity we can easily determine the expected display rotation. | |
| 156 static gfx::Vector3dF rotation_reference(-1.0f, 1.0f, 0.0f); | |
| 157 | |
| 158 // Set the down vector to match the expected direction of gravity given the | |
| 159 // last configured rotation. This is used to enforce a stickiness that the | |
| 160 // user must overcome to rotate the display and prevents frequent rotations | |
| 161 // when holding the device near 45 degrees. | |
| 162 gfx::Vector3dF down(0.0f, 0.0f, 0.0f); | |
| 163 if (current_rotation == gfx::Display::ROTATE_0) | |
| 164 down.set_x(-1.0f); | |
| 165 else if (current_rotation == gfx::Display::ROTATE_90) | |
| 166 down.set_y(1.0f); | |
| 167 else if (current_rotation == gfx::Display::ROTATE_180) | |
| 168 down.set_x(1.0f); | |
| 169 else | |
| 170 down.set_y(-1.0f); | |
| 171 | |
| 172 // Don't rotate if the screen has not passed the threshold. | |
| 173 if (AngleBetweenVectorsInDegrees(down, lid_flattened) < | |
| 174 kDisplayRotationStickyAngleDegrees) { | |
| 175 return; | |
| 176 } | |
| 177 | |
| 178 float angle = ClockwiseAngleBetweenVectorsInDegrees(rotation_reference, | |
| 179 lid_flattened, gfx::Vector3dF(0.0f, 0.0f, -1.0f)); | |
| 180 | |
| 181 gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_90; | |
| 182 if (angle < 90.0f) | |
| 183 new_rotation = gfx::Display::ROTATE_0; | |
| 184 else if (angle < 180.0f) | |
| 185 new_rotation = gfx::Display::ROTATE_270; | |
| 186 else if (angle < 270.0f) | |
| 187 new_rotation = gfx::Display::ROTATE_180; | |
| 188 | |
| 189 // When exiting maximize mode return rotation to 0. When entering, rotate to | |
| 190 // match screen orientation. | |
| 191 if (new_rotation == gfx::Display::ROTATE_0 || | |
| 192 maximize_mode_engaged) { | |
| 193 display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(), | |
| 194 new_rotation); | |
| 195 } | |
| 196 } | |
| 197 | |
| 103 } // namespace ash | 198 } // namespace ash |
| OLD | NEW |