blob: 2671bc30549fdfb06aca7d7c905c3e98781cf263 [file] [log] [blame]
// Copyright 2016 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 "ash/display/touch_calibrator_controller.h"
#include "ash/display/touch_calibrator_view.h"
#include "ash/shell.h"
#include "ash/touch/ash_touch_transform_controller.h"
#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
namespace ash {
// Time interval after a touch event during which all other touch events are
// ignored during calibration.
const base::TimeDelta TouchCalibratorController::kTouchIntervalThreshold =
base::TimeDelta::FromMilliseconds(200);
TouchCalibratorController::TouchCalibratorController()
: last_touch_timestamp_(base::Time::Now()) {}
TouchCalibratorController::~TouchCalibratorController() {
touch_calibrator_views_.clear();
StopCalibration();
}
void TouchCalibratorController::OnDisplayConfigurationChanged() {
touch_calibrator_views_.clear();
StopCalibration();
}
void TouchCalibratorController::StartCalibration(
const display::Display& target_display,
const TouchCalibratorController::TouchCalibrationCallback& callback) {
is_calibrating_ = true;
callback_ = callback;
Shell::Get()->window_tree_host_manager()->AddObserver(this);
target_display_ = target_display;
// Clear all touch calibrator views used in any previous calibration.
touch_calibrator_views_.clear();
// Reset the calibration data.
touch_point_quad_.fill(std::make_pair(gfx::Point(0, 0), gfx::Point(0, 0)));
std::vector<display::Display> displays =
display::Screen::GetScreen()->GetAllDisplays();
for (const display::Display& display : displays) {
bool is_primary_view = display.id() == target_display_.id();
touch_calibrator_views_[display.id()] =
base::MakeUnique<TouchCalibratorView>(display, is_primary_view);
}
Shell::Get()->touch_transformer_controller()->SetForCalibration(true);
// Add self as an event handler target.
Shell::Get()->AddPreTargetHandler(this);
}
void TouchCalibratorController::StopCalibration() {
if (!is_calibrating_)
return;
is_calibrating_ = false;
Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
Shell::Get()->touch_transformer_controller()->SetForCalibration(false);
// Remove self as the event handler.
Shell::Get()->RemovePreTargetHandler(this);
// Transition all touch calibrator views to their final state for a graceful
// exit.
for (const auto& it : touch_calibrator_views_)
it.second->SkipToFinalState();
if (callback_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
base::Bind(callback_, false));
callback_.Reset();
}
}
// ui::EventHandler:
void TouchCalibratorController::OnKeyEvent(ui::KeyEvent* key) {
if (!is_calibrating_)
return;
// Detect ESC key press.
if (key->type() == ui::ET_KEY_PRESSED && key->key_code() == ui::VKEY_ESCAPE)
StopCalibration();
key->StopPropagation();
}
void TouchCalibratorController::OnTouchEvent(ui::TouchEvent* touch) {
if (!is_calibrating_)
return;
if (touch->type() != ui::ET_TOUCH_RELEASED)
return;
if (base::Time::Now() - last_touch_timestamp_ < kTouchIntervalThreshold)
return;
last_touch_timestamp_ = base::Time::Now();
TouchCalibratorView* target_screen_calibration_view =
touch_calibrator_views_[target_display_.id()].get();
// If this is the final state, then store all calibration data and stop
// calibration.
if (target_screen_calibration_view->state() ==
TouchCalibratorView::CALIBRATION_COMPLETE) {
if (callback_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback_, true));
callback_.Reset();
}
StopCalibration();
Shell::Get()->display_manager()->SetTouchCalibrationData(
target_display_.id(), touch_point_quad_,
target_screen_calibration_view->size());
return;
}
int state_index;
// Maps the state to an integer value. Assigns a non negative integral value
// for a state in which the user can interact with the the interface.
switch (target_screen_calibration_view->state()) {
case TouchCalibratorView::DISPLAY_POINT_1:
state_index = 0;
break;
case TouchCalibratorView::DISPLAY_POINT_2:
state_index = 1;
break;
case TouchCalibratorView::DISPLAY_POINT_3:
state_index = 2;
break;
case TouchCalibratorView::DISPLAY_POINT_4:
state_index = 3;
break;
default:
// Return early if the interface is in a state that does not allow user
// interaction.
return;
}
// Store touch point corresponding to its display point.
gfx::Point display_point;
if (target_screen_calibration_view->GetDisplayPointLocation(&display_point)) {
touch_point_quad_[state_index] =
std::make_pair(display_point, touch->location());
} else {
// TODO(malaykeshav): Display some kind of error for the user.
NOTREACHED() << "Touch calibration failed. Could not retrieve location for"
" display point. Retry calibration.";
}
target_screen_calibration_view->AdvanceToNextState();
}
} // namespace ash