Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ash / wm / maximize_mode / maximize_mode_controller.cc
index add7fb3..dc78d28 100644 (file)
@@ -19,7 +19,6 @@
 #include "base/time/tick_clock.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/events/event.h"
-#include "ui/events/event_handler.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/vector3d_f.h"
 
@@ -56,34 +55,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;
 
@@ -110,53 +112,13 @@ float ClockwiseAngleBetweenVectorsInDegrees(const gfx::Vector3dF& base,
   return angle;
 }
 
-#if defined(OS_CHROMEOS)
-
-// An event handler which listens for a volume down + power keypress and
-// triggers a screenshot when this is seen.
-class ScreenshotActionHandler : public ui::EventHandler {
- public:
-  ScreenshotActionHandler();
-  virtual ~ScreenshotActionHandler();
-
-  // ui::EventHandler:
-  virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
-
- private:
-  bool volume_down_pressed_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScreenshotActionHandler);
-};
-
-ScreenshotActionHandler::ScreenshotActionHandler()
-    : volume_down_pressed_(false) {
-  Shell::GetInstance()->PrependPreTargetHandler(this);
-}
-
-ScreenshotActionHandler::~ScreenshotActionHandler() {
-  Shell::GetInstance()->RemovePreTargetHandler(this);
-}
-
-void ScreenshotActionHandler::OnKeyEvent(ui::KeyEvent* event) {
-  if (event->key_code() == ui::VKEY_VOLUME_DOWN) {
-    volume_down_pressed_ = event->type() == ui::ET_KEY_PRESSED ||
-                           event->type() == ui::ET_TRANSLATED_KEY_PRESS;
-  } else if (volume_down_pressed_ &&
-             event->key_code() == ui::VKEY_POWER &&
-             event->type() == ui::ET_KEY_PRESSED) {
-    Shell::GetInstance()->accelerator_controller()->PerformAction(
-        ash::TAKE_SCREENSHOT, ui::Accelerator());
-  }
-}
-
-#endif  // OS_CHROMEOS
-
 }  // namespace
 
 MaximizeModeController::MaximizeModeController()
     : rotation_locked_(false),
       have_seen_accelerometer_data_(false),
-      in_set_screen_rotation_(false),
+      ignore_display_configuration_updates_(false),
+      shutting_down_(false),
       user_rotation_(gfx::Display::ROTATE_0),
       last_touchview_transition_time_(base::Time::Now()),
       tick_clock_(new base::DefaultTickClock()),
@@ -181,7 +143,11 @@ MaximizeModeController::~MaximizeModeController() {
 void MaximizeModeController::SetRotationLocked(bool rotation_locked) {
   if (rotation_locked_ == rotation_locked)
     return;
+  base::AutoReset<bool> auto_ignore_display_configuration_updates(
+      &ignore_display_configuration_updates_, true);
   rotation_locked_ = rotation_locked;
+  Shell::GetInstance()->display_manager()->
+      RegisterDisplayRotationProperties(rotation_locked_, current_rotation_);
   FOR_EACH_OBSERVER(Observer, observers_,
                     OnRotationLockChanged(rotation_locked_));
 }
@@ -226,34 +192,52 @@ void MaximizeModeController::AddWindow(aura::Window* window) {
 }
 
 void MaximizeModeController::Shutdown() {
-  maximize_mode_window_manager_.reset();
-  Shell::GetInstance()->OnMaximizeModeEnded();
+  shutting_down_ = true;
+  LeaveMaximizeMode();
 }
 
 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));
+  }
+  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
+    // maximize mode or not. Update the preferences to reflect the current
+    // state.
+    Shell::GetInstance()->display_manager()->
+        RegisterDisplayRotationProperties(rotation_locked_, current_rotation_);
   }
-
-  // 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);
 }
 
 void MaximizeModeController::OnDisplayConfigurationChanged() {
-  if (in_set_screen_rotation_)
+  if (ignore_display_configuration_updates_)
     return;
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
   gfx::Display::Rotation user_rotation = display_manager->
@@ -289,14 +273,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.
@@ -307,10 +291,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
@@ -323,10 +310,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();
   }
@@ -358,7 +345,7 @@ 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
@@ -366,13 +353,13 @@ void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) {
   // 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) <
@@ -398,8 +385,8 @@ void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) {
 void MaximizeModeController::SetDisplayRotation(
     DisplayManager* display_manager,
     gfx::Display::Rotation rotation) {
-  base::AutoReset<bool> auto_in_set_screen_rotation(
-      &in_set_screen_rotation_, true);
+  base::AutoReset<bool> auto_ignore_display_configuration_updates(
+      &ignore_display_configuration_updates_, true);
   current_rotation_ = rotation;
   display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(),
                                       rotation);
@@ -409,15 +396,15 @@ void MaximizeModeController::EnterMaximizeMode() {
   if (IsMaximizeModeWindowManagerEnabled())
     return;
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  current_rotation_ = user_rotation_ = display_manager->
-      GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
+  if (display_manager->HasInternalDisplay()) {
+    current_rotation_ = user_rotation_ = display_manager->
+        GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
+    LoadDisplayRotationProperties();
+  }
   EnableMaximizeModeWindowManager(true);
 #if defined(USE_X11)
   event_blocker_.reset(new ScopedDisableInternalMouseAndKeyboardX11);
 #endif
-#if defined(OS_CHROMEOS)
-  event_handler_.reset(new ScreenshotActionHandler);
-#endif
   Shell::GetInstance()->display_controller()->AddObserver(this);
 }
 
@@ -425,14 +412,16 @@ void MaximizeModeController::LeaveMaximizeMode() {
   if (!IsMaximizeModeWindowManagerEnabled())
     return;
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  gfx::Display::Rotation current_rotation = display_manager->
-      GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
-  if (current_rotation != user_rotation_)
-    SetDisplayRotation(display_manager, user_rotation_);
-  rotation_locked_ = false;
+  if (display_manager->HasInternalDisplay()) {
+    gfx::Display::Rotation current_rotation = display_manager->
+        GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
+    if (current_rotation != user_rotation_)
+      SetDisplayRotation(display_manager, user_rotation_);
+  }
+  if (!shutting_down_)
+    SetRotationLocked(false);
   EnableMaximizeModeWindowManager(false);
   event_blocker_.reset();
-  event_handler_.reset();
   Shell::GetInstance()->display_controller()->RemoveObserver(this);
 }
 
@@ -462,6 +451,16 @@ void MaximizeModeController::RecordTouchViewStateTransition() {
   }
 }
 
+void MaximizeModeController::LoadDisplayRotationProperties() {
+  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
+  if (!display_manager->registered_internal_display_rotation_lock())
+    return;
+
+  SetDisplayRotation(display_manager,
+                     display_manager->registered_internal_display_rotation());
+  SetRotationLocked(true);
+}
+
 void MaximizeModeController::OnAppTerminating() {
   if (CanEnterMaximizeMode()) {
     RecordTouchViewStateTransition();