Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(875)

Side by Side Diff: ash/wm/maximize_mode/maximize_mode_controller.cc

Issue 412013002: Prevent entering maximize mode when the lid is closed or has recently opened. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/accelerators/accelerator_controller.h" 7 #include "ash/accelerators/accelerator_controller.h"
8 #include "ash/accelerators/accelerator_table.h" 8 #include "ash/accelerators/accelerator_table.h"
9 #include "ash/accelerometer/accelerometer_controller.h" 9 #include "ash/accelerometer/accelerometer_controller.h"
10 #include "ash/ash_switches.h" 10 #include "ash/ash_switches.h"
11 #include "ash/display/display_manager.h" 11 #include "ash/display/display_manager.h"
12 #include "ash/shell.h" 12 #include "ash/shell.h"
13 #include "ash/wm/maximize_mode/maximize_mode_window_manager.h" 13 #include "ash/wm/maximize_mode/maximize_mode_window_manager.h"
14 #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" 14 #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h"
15 #include "base/auto_reset.h" 15 #include "base/auto_reset.h"
16 #include "base/command_line.h" 16 #include "base/command_line.h"
17 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
18 #include "chromeos/dbus/dbus_thread_manager.h"
jonross 2014/07/24 14:22:00 Can you confirm via gyp files that this will alway
bruthig 2014/07/24 19:57:06 Done.
18 #include "ui/base/accelerators/accelerator.h" 19 #include "ui/base/accelerators/accelerator.h"
19 #include "ui/events/event.h" 20 #include "ui/events/event.h"
20 #include "ui/events/event_handler.h" 21 #include "ui/events/event_handler.h"
21 #include "ui/events/keycodes/keyboard_codes.h" 22 #include "ui/events/keycodes/keyboard_codes.h"
22 #include "ui/gfx/vector3d_f.h" 23 #include "ui/gfx/vector3d_f.h"
23 24
24 #if defined(USE_X11) 25 #if defined(USE_X11)
25 #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h" 26 #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h"
26 #endif 27 #endif
27 28
28 namespace ash { 29 namespace ash {
29 30
30 namespace { 31 namespace {
31 32
32 // The hinge angle at which to enter maximize mode. 33 // The hinge angle at which to enter maximize mode.
33 const float kEnterMaximizeModeAngle = 200.0f; 34 const float kEnterMaximizeModeAngle = 200.0f;
34 35
35 // The angle at which to exit maximize mode, this is specifically less than the 36 // The angle at which to exit maximize mode, this is specifically less than the
36 // angle to enter maximize mode to prevent rapid toggling when near the angle. 37 // angle to enter maximize mode to prevent rapid toggling when near the angle.
37 const float kExitMaximizeModeAngle = 160.0f; 38 const float kExitMaximizeModeAngle = 160.0f;
38 39
39 // When the lid is fully open 360 degrees, the accelerometer readings can 40 // Defines a range for which accelerometer readings are considered accurate.
40 // occasionally appear as though the lid is almost closed. If the lid appears 41 // When the lid is near open (or near closed) the acceleromter readings may be
41 // near closed but the device is on we assume it is an erroneous reading from 42 // inaccurate and a lid that is fully open may appear to be near closed (and
42 // it being open 360 degrees. 43 // vice versa).
43 const float kFullyOpenAngleErrorTolerance = 20.0f; 44 const float kMinStableAngle = 20.0f;
45 const float kMaxStableAngle = 340.0f;
46
47 // The time in seconds to consider the lid to be recently opened.
48 // This is used to prevent entering maximize mode if an erroneous accelerometer
49 // reading makes the lid appear to be fully open when the user is opening the
50 // lid from a closed position.
51 const int kLidRecentlyOpenedTolerance = 2;
jonross 2014/07/24 14:22:00 For constants representing a time duration we appe
bruthig 2014/07/24 19:57:06 Done.
44 52
45 // When the device approaches vertical orientation (i.e. portrait orientation) 53 // When the device approaches vertical orientation (i.e. portrait orientation)
46 // the accelerometers for the base and lid approach the same values (i.e. 54 // the accelerometers for the base and lid approach the same values (i.e.
47 // gravity pointing in the direction of the hinge). When this happens we cannot 55 // gravity pointing in the direction of the hinge). When this happens we cannot
48 // compute the hinge angle reliably and must turn ignore accelerometer readings. 56 // compute the hinge angle reliably and must turn ignore accelerometer readings.
49 // This is the minimum acceleration perpendicular to the hinge under which to 57 // This is the minimum acceleration perpendicular to the hinge under which to
50 // detect hinge angle. 58 // detect hinge angle.
51 const float kHingeAngleDetectionThreshold = 0.25f; 59 const float kHingeAngleDetectionThreshold = 0.25f;
52 60
53 // The maximum deviation from the acceleration expected due to gravity under 61 // The maximum deviation from the acceleration expected due to gravity under
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 event->type() == ui::ET_KEY_PRESSED) { 140 event->type() == ui::ET_KEY_PRESSED) {
133 Shell::GetInstance()->accelerator_controller()->PerformAction( 141 Shell::GetInstance()->accelerator_controller()->PerformAction(
134 ash::TAKE_SCREENSHOT, ui::Accelerator()); 142 ash::TAKE_SCREENSHOT, ui::Accelerator());
135 } 143 }
136 } 144 }
137 145
138 #endif // OS_CHROMEOS 146 #endif // OS_CHROMEOS
139 147
140 } // namespace 148 } // namespace
141 149
150 base::TimeTicks MaximizeModeController::TimeTickProviderImpl::Now() const {
151 return base::TimeTicks::Now();
152 }
153
142 MaximizeModeController::MaximizeModeController() 154 MaximizeModeController::MaximizeModeController()
143 : rotation_locked_(false), 155 : rotation_locked_(false),
144 have_seen_accelerometer_data_(false), 156 have_seen_accelerometer_data_(false),
145 in_set_screen_rotation_(false), 157 in_set_screen_rotation_(false),
146 user_rotation_(gfx::Display::ROTATE_0), 158 user_rotation_(gfx::Display::ROTATE_0),
147 last_touchview_transition_time_(base::Time::Now()) { 159 last_touchview_transition_time_(base::Time::Now()),
160 last_lid_open_time_(),
161 time_tick_provider_(new TimeTickProviderImpl()),
162 lid_is_closed_(false) {
148 Shell::GetInstance()->accelerometer_controller()->AddObserver(this); 163 Shell::GetInstance()->accelerometer_controller()->AddObserver(this);
149 Shell::GetInstance()->AddShellObserver(this); 164 Shell::GetInstance()->AddShellObserver(this);
165 chromeos::DBusThreadManager::Get()->
166 GetPowerManagerClient()->AddObserver(this);
150 } 167 }
151 168
152 MaximizeModeController::~MaximizeModeController() { 169 MaximizeModeController::~MaximizeModeController() {
153 Shell::GetInstance()->RemoveShellObserver(this); 170 Shell::GetInstance()->RemoveShellObserver(this);
154 Shell::GetInstance()->accelerometer_controller()->RemoveObserver(this); 171 Shell::GetInstance()->accelerometer_controller()->RemoveObserver(this);
172 chromeos::DBusThreadManager::Get()->
173 GetPowerManagerClient()->RemoveObserver(this);
155 } 174 }
156 175
157 void MaximizeModeController::SetRotationLocked(bool rotation_locked) { 176 void MaximizeModeController::SetRotationLocked(bool rotation_locked) {
158 if (rotation_locked_ == rotation_locked) 177 if (rotation_locked_ == rotation_locked)
159 return; 178 return;
160 rotation_locked_ = rotation_locked; 179 rotation_locked_ = rotation_locked;
161 FOR_EACH_OBSERVER(Observer, observers_, 180 FOR_EACH_OBSERVER(Observer, observers_,
162 OnRotationLockChanged(rotation_locked_)); 181 OnRotationLockChanged(rotation_locked_));
163 } 182 }
164 183
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 if (user_rotation != current_rotation_) { 251 if (user_rotation != current_rotation_) {
233 // A user may change other display configuration settings. When the user 252 // A user may change other display configuration settings. When the user
234 // does change the rotation setting, then lock rotation to prevent the 253 // does change the rotation setting, then lock rotation to prevent the
235 // accelerometer from erasing their change. 254 // accelerometer from erasing their change.
236 SetRotationLocked(true); 255 SetRotationLocked(true);
237 user_rotation_ = user_rotation; 256 user_rotation_ = user_rotation;
238 current_rotation_ = user_rotation; 257 current_rotation_ = user_rotation;
239 } 258 }
240 } 259 }
241 260
261 void MaximizeModeController::LidEventReceived(bool open,
262 const base::TimeTicks& time) {
263 if (open)
264 last_lid_open_time_ = time;
265 lid_is_closed_ = !open;
266 LeaveMaximizeMode();
267 }
268
269 void MaximizeModeController::SuspendImminent() {
270 RecordTouchViewStateTransition();
271 }
272
273 void MaximizeModeController::SuspendDone(
274 const base::TimeDelta& sleep_duration) {
275 last_touchview_transition_time_ = base::Time::Now();
276 // A lid open event won't always occur when coming out of a suspend state.
jonross 2014/07/24 14:22:00 If it does not, is there a way to poll lid state u
bruthig 2014/07/24 19:57:06 I'm not sure if there is a way or not but I don't
jonross 2014/07/25 13:39:06 Acknowledged.
277 lid_is_closed_ = false;
278 }
279
242 void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base, 280 void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base,
243 const gfx::Vector3dF& lid) { 281 const gfx::Vector3dF& lid) {
244 static const gfx::Vector3dF hinge_vector(0.0f, 1.0f, 0.0f); 282 static const gfx::Vector3dF hinge_vector(0.0f, 1.0f, 0.0f);
245 bool maximize_mode_engaged = IsMaximizeModeWindowManagerEnabled();
246 // Ignore the component of acceleration parallel to the hinge for the purposes 283 // Ignore the component of acceleration parallel to the hinge for the purposes
247 // of hinge angle calculation. 284 // of hinge angle calculation.
248 gfx::Vector3dF base_flattened(base); 285 gfx::Vector3dF base_flattened(base);
249 gfx::Vector3dF lid_flattened(lid); 286 gfx::Vector3dF lid_flattened(lid);
250 base_flattened.set_y(0.0f); 287 base_flattened.set_y(0.0f);
251 lid_flattened.set_y(0.0f); 288 lid_flattened.set_y(0.0f);
252 289
253 // As the hinge approaches a vertical angle, the base and lid accelerometers 290 // As the hinge approaches a vertical angle, the base and lid accelerometers
254 // approach the same values making any angle calculations highly inaccurate. 291 // approach the same values making any angle calculations highly inaccurate.
255 // Bail out early when it is too close. 292 // Bail out early when it is too close.
256 if (base_flattened.Length() < kHingeAngleDetectionThreshold || 293 if (base_flattened.Length() < kHingeAngleDetectionThreshold ||
257 lid_flattened.Length() < kHingeAngleDetectionThreshold) { 294 lid_flattened.Length() < kHingeAngleDetectionThreshold) {
258 return; 295 return;
259 } 296 }
260 297
261 // Compute the angle between the base and the lid. 298 // Compute the angle between the base and the lid.
262 float angle = ClockwiseAngleBetweenVectorsInDegrees(base_flattened, 299 float angle = ClockwiseAngleBetweenVectorsInDegrees(base_flattened,
263 lid_flattened, hinge_vector); 300 lid_flattened, hinge_vector);
264
265 // Toggle maximize mode on or off when corresponding thresholds are passed. 301 // Toggle maximize mode on or off when corresponding thresholds are passed.
266 // TODO(flackr): Make MaximizeModeController own the MaximizeModeWindowManager 302 // TODO(flackr): Make MaximizeModeController own the MaximizeModeWindowManager
267 // such that observations of state changes occur after the change and shell 303 // such that observations of state changes occur after the change and shell
268 // has fewer states to track. 304 // has fewer states to track.
269 if (maximize_mode_engaged && 305 if (lid_is_closed_) {
270 angle > kFullyOpenAngleErrorTolerance &&
271 angle < kExitMaximizeModeAngle) {
272 LeaveMaximizeMode(); 306 LeaveMaximizeMode();
273 } else if (!maximize_mode_engaged && 307 } else if (angle > kMinStableAngle &&
jonross 2014/07/24 14:22:00 Should we exit MaximizeMode if angle <kMinStableAn
bruthig 2014/07/24 19:57:06 No we don't want to exit MaximizeMode in this case
jonross 2014/07/25 13:39:06 Acknowledged.
274 angle > kEnterMaximizeModeAngle) { 308 angle < kMaxStableAngle) {
275 EnterMaximizeMode(); 309 // Clear the last_lid_open_time_ for a stable reading so that there is less
310 // chance of a delay if the lid is moved from the close state to the fully
311 // open state very quickly.
312 last_lid_open_time_ = base::TimeTicks();
jonross 2014/07/24 14:22:00 This moves the lid open time to be later than when
bruthig 2014/07/24 19:57:06 I don't think this is doing what you think. It's
jonross 2014/07/25 13:39:06 My misreading.
313 if (angle < kExitMaximizeModeAngle) {
314 LeaveMaximizeMode();
315 } else if (angle > kEnterMaximizeModeAngle) {
316 EnterMaximizeMode();
317 }
318 } else if (angle > kMaxStableAngle) {
319 if (WasLidOpenedRecently()) {
320 LeaveMaximizeMode();
321 } else {
322 EnterMaximizeMode();
323 }
276 } 324 }
277 } 325 }
278 326
279 void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) { 327 void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) {
280 bool maximize_mode_engaged = IsMaximizeModeWindowManagerEnabled(); 328 bool maximize_mode_engaged = IsMaximizeModeWindowManagerEnabled();
281 329
282 // TODO(jonross): track the updated rotation angle even when locked. So that 330 // TODO(jonross): track the updated rotation angle even when locked. So that
283 // when rotation lock is removed the accelerometer rotation can be applied 331 // when rotation lock is removed the accelerometer rotation can be applied
284 // without waiting for the next update. 332 // without waiting for the next update.
285 if (!maximize_mode_engaged || rotation_locked_) 333 if (!maximize_mode_engaged || rotation_locked_)
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 DisplayManager* display_manager, 391 DisplayManager* display_manager,
344 gfx::Display::Rotation rotation) { 392 gfx::Display::Rotation rotation) {
345 base::AutoReset<bool> auto_in_set_screen_rotation( 393 base::AutoReset<bool> auto_in_set_screen_rotation(
346 &in_set_screen_rotation_, true); 394 &in_set_screen_rotation_, true);
347 current_rotation_ = rotation; 395 current_rotation_ = rotation;
348 display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(), 396 display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(),
349 rotation); 397 rotation);
350 } 398 }
351 399
352 void MaximizeModeController::EnterMaximizeMode() { 400 void MaximizeModeController::EnterMaximizeMode() {
401 if (IsMaximizeModeWindowManagerEnabled())
jonross 2014/07/24 14:22:00 We should stop calling this twice.
bruthig 2014/07/24 19:57:06 In order to stop calling it twice each spot that c
402 return;
353 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 403 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
354 current_rotation_ = user_rotation_ = display_manager-> 404 current_rotation_ = user_rotation_ = display_manager->
355 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 405 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
356 EnableMaximizeModeWindowManager(true); 406 EnableMaximizeModeWindowManager(true);
357 #if defined(USE_X11) 407 #if defined(USE_X11)
358 event_blocker_.reset(new ScopedDisableInternalMouseAndKeyboardX11); 408 event_blocker_.reset(new ScopedDisableInternalMouseAndKeyboardX11);
359 #endif 409 #endif
360 #if defined(OS_CHROMEOS) 410 #if defined(OS_CHROMEOS)
361 event_handler_.reset(new ScreenshotActionHandler); 411 event_handler_.reset(new ScreenshotActionHandler);
362 #endif 412 #endif
363 Shell::GetInstance()->display_controller()->AddObserver(this); 413 Shell::GetInstance()->display_controller()->AddObserver(this);
364 } 414 }
365 415
366 void MaximizeModeController::LeaveMaximizeMode() { 416 void MaximizeModeController::LeaveMaximizeMode() {
417 if (!IsMaximizeModeWindowManagerEnabled())
418 return;
367 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 419 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
368 gfx::Display::Rotation current_rotation = display_manager-> 420 gfx::Display::Rotation current_rotation = display_manager->
369 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 421 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
370 if (current_rotation != user_rotation_) 422 if (current_rotation != user_rotation_)
371 SetDisplayRotation(display_manager, user_rotation_); 423 SetDisplayRotation(display_manager, user_rotation_);
372 rotation_locked_ = false; 424 rotation_locked_ = false;
373 EnableMaximizeModeWindowManager(false); 425 EnableMaximizeModeWindowManager(false);
374 event_blocker_.reset(); 426 event_blocker_.reset();
375 event_handler_.reset(); 427 event_handler_.reset();
376 } 428 Shell::GetInstance()->display_controller()->RemoveObserver(this);
jonross 2014/07/24 14:22:00 Nice fix.
377
378 void MaximizeModeController::OnSuspend() {
379 RecordTouchViewStateTransition();
380 }
381
382 void MaximizeModeController::OnResume() {
383 last_touchview_transition_time_ = base::Time::Now();
384 } 429 }
385 430
386 // Called after maximize mode has started, windows might still animate though. 431 // Called after maximize mode has started, windows might still animate though.
387 void MaximizeModeController::OnMaximizeModeStarted() { 432 void MaximizeModeController::OnMaximizeModeStarted() {
388 RecordTouchViewStateTransition(); 433 RecordTouchViewStateTransition();
389 } 434 }
390 435
391 // Called after maximize mode has ended, windows might still be returning to 436 // Called after maximize mode has ended, windows might still be returning to
392 // their original position. 437 // their original position.
393 void MaximizeModeController::OnMaximizeModeEnded() { 438 void MaximizeModeController::OnMaximizeModeEnded() {
(...skipping 27 matching lines...) Expand all
421 base::TimeDelta total_runtime = total_touchview_time_ + 466 base::TimeDelta total_runtime = total_touchview_time_ +
422 total_non_touchview_time_; 467 total_non_touchview_time_;
423 if (total_runtime.InSeconds() > 0) { 468 if (total_runtime.InSeconds() > 0) {
424 UMA_HISTOGRAM_PERCENTAGE("Ash.TouchView.TouchViewActivePercentage", 469 UMA_HISTOGRAM_PERCENTAGE("Ash.TouchView.TouchViewActivePercentage",
425 100 * total_touchview_time_.InSeconds() / total_runtime.InSeconds()); 470 100 * total_touchview_time_.InSeconds() / total_runtime.InSeconds());
426 } 471 }
427 } 472 }
428 Shell::GetInstance()->display_controller()->RemoveObserver(this); 473 Shell::GetInstance()->display_controller()->RemoveObserver(this);
429 } 474 }
430 475
476 bool MaximizeModeController::WasLidOpenedRecently() const {
477 bool was_lid_recently_opened = false;
478 if (!last_lid_open_time_.is_null()) {
jonross 2014/07/24 14:22:00 Quick exits are prefered. if (last_lid_open_time_
bruthig 2014/07/24 19:57:06 Done.
479 base::TimeTicks now = time_tick_provider_->Now();
480 DCHECK(now >= last_lid_open_time_);
481 base::TimeDelta elapsed_time = now - last_lid_open_time_;
482 was_lid_recently_opened =
483 elapsed_time <= base::TimeDelta::FromSeconds(kLidRecentlyOpenedTolerance);
484 }
485 return was_lid_recently_opened;
486 }
487
488 void MaximizeModeController::SetTimeTickProviderForTest(
489 TimeTickProvider* provider) {
490 DCHECK(provider);
491 time_tick_provider_.reset(provider);
492 }
493
431 } // namespace ash 494 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698