Commit 84fdb54e authored by James Cook's avatar James Cook Committed by Commit Bot

cros: Clean up TouchHudApplication in preparation for adding tests

In a later CL I'm creating and tearing down the UI widgets for the
touch HUD app, which revealed problems with widget ownership and
child views::View teardown.

* Use a single PointerWatcher across all displays (since PointerWatcher
  tracks events on all displays)
* Fork ash::TouchHudRenderer. The legacy ash one will go away when the
  mojo app becomes the default.
* Make the app own the TouchHudRenderers and TouchHudRenderer own the
  views::Widget.

TODO: Eliminate Launchable interface.

Tbr: sky@chromium.org
Bug: 840380
Test: chrome --show-taps-app paints touch points
Change-Id: Icba099a00f284835099af244db8afd93b9ed7a48
Reviewed-on: https://chromium-review.googlesource.com/1060523Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarkylechar <kylechar@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarMichael Wasserman <msw@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#559304}
parent debda5e4
......@@ -11,17 +11,24 @@ source_set("lib") {
sources = [
"touch_hud_application.cc",
"touch_hud_application.h",
"touch_hud_renderer.cc",
"touch_hud_renderer.h",
]
deps = [
"//ash/public/cpp",
"//ash/touch_hud",
"//base",
"//cc/paint",
"//mash/public/mojom",
"//mojo/public/cpp/bindings",
"//services/service_manager/public/cpp",
"//services/ui/public/cpp",
"//services/ui/public/interfaces",
"//skia",
"//ui/compositor",
"//ui/events",
"//ui/gfx",
"//ui/gfx/geometry",
"//ui/views",
"//ui/views/mus:for_mojo_application",
]
......
include_rules = [
"+ash/public",
"+ash/touch_hud",
"+base",
"+cc/paint",
"+mash/public/mojom",
"+mojo/public",
"+services/service_manager/public",
"+services/ui/public",
"+third_party/skia",
"+ui/aura",
"+ui/compositor",
"+ui/events",
"+ui/display",
"+ui/gfx",
"+ui/views",
]
......@@ -6,8 +6,8 @@
#include <utility>
#include "ash/components/touch_hud/touch_hud_renderer.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/touch_hud/touch_hud_renderer.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "services/service_manager/public/cpp/connector.h"
......@@ -25,53 +25,6 @@
#include "ui/views/widget/widget_delegate.h"
namespace touch_hud {
namespace {
// TouchHudUI handles events on the widget of the touch-hud app. After
// receiving touch events from PointerWatcher, it calls ash::TouchHudRenderer to
// draw the touch points.
class TouchHudUI : public views::WidgetDelegateView,
public views::PointerWatcher {
public:
explicit TouchHudUI(views::Widget* widget)
: touch_hud_renderer_(std::make_unique<ash::TouchHudRenderer>(widget)) {
// Watches moves so the user can drag around a touch point.
views::MusClient::Get()->pointer_watcher_event_router()->AddPointerWatcher(
this, true /* want_moves */);
}
~TouchHudUI() override {
views::MusClient::Get()
->pointer_watcher_event_router()
->RemovePointerWatcher(this);
}
private:
// Overridden from views::WidgetDelegate:
base::string16 GetWindowTitle() const override {
// TODO(beng): use resources.
return base::ASCIIToUTF16("TouchHud");
}
// Overridden from views::PointerWatcher:
void OnPointerEventObserved(const ui::PointerEvent& event,
const gfx::Point& location_in_screen,
gfx::NativeView target) override {
if (!event.IsTouchPointerEvent())
return;
// Ignore taps on other displays.
if (!GetWidget()->GetWindowBoundsInScreen().Contains(location_in_screen))
return;
touch_hud_renderer_->HandleTouchEvent(event);
}
std::unique_ptr<ash::TouchHudRenderer> touch_hud_renderer_;
DISALLOW_COPY_AND_ASSIGN(TouchHudUI);
};
} // namespace
TouchHudApplication::TouchHudApplication() : binding_(this) {
registry_.AddInterface<mash::mojom::Launchable>(base::BindRepeating(
......@@ -80,6 +33,8 @@ TouchHudApplication::TouchHudApplication() : binding_(this) {
TouchHudApplication::~TouchHudApplication() {
display::Screen::GetScreen()->RemoveObserver(this);
views::MusClient::Get()->pointer_watcher_event_router()->RemovePointerWatcher(
this);
}
void TouchHudApplication::OnStart() {
......@@ -92,7 +47,6 @@ void TouchHudApplication::OnStart() {
context()->QuitNow();
return;
}
display::Screen::GetScreen()->AddObserver(this);
Launch(mash::mojom::kWindow, mash::mojom::LaunchMode::DEFAULT);
}
......@@ -104,20 +58,41 @@ void TouchHudApplication::OnBindInterface(
}
void TouchHudApplication::Launch(uint32_t what, mash::mojom::LaunchMode how) {
// Watches moves so the user can drag around a touch point.
views::MusClient::Get()->pointer_watcher_event_router()->AddPointerWatcher(
this, true /* want_moves */);
display::Screen::GetScreen()->AddObserver(this);
for (const display::Display& display :
display::Screen::GetScreen()->GetAllDisplays()) {
CreateWidgetForDisplay(display.id());
}
}
void TouchHudApplication::OnPointerEventObserved(
const ui::PointerEvent& event,
const gfx::Point& location_in_screen,
gfx::NativeView target) {
if (!event.IsTouchPointerEvent())
return;
int64_t display_id = display::Screen::GetScreen()
->GetDisplayNearestPoint(location_in_screen)
.id();
auto it = display_id_to_renderer_.find(display_id);
if (it != display_id_to_renderer_.end()) {
TouchHudRenderer* renderer = it->second.get();
renderer->HandleTouchEvent(event);
}
}
void TouchHudApplication::OnDisplayAdded(const display::Display& new_display) {
CreateWidgetForDisplay(new_display.id());
}
void TouchHudApplication::OnDisplayRemoved(
const display::Display& old_display) {
// Deletes the widget.
display_id_to_widget_.erase(old_display.id());
// Deletes the renderer.
display_id_to_renderer_.erase(old_display.id());
}
void TouchHudApplication::CreateWidgetForDisplay(int64_t display_id) {
......@@ -128,7 +103,7 @@ void TouchHudApplication::CreateWidgetForDisplay(int64_t display_id) {
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
params.accept_events = false;
params.delegate = new TouchHudUI(widget.get());
params.delegate = new views::WidgetDelegateView;
params.mus_properties[ui::mojom::WindowManager::kContainerId_InitProperty] =
mojo::ConvertTo<std::vector<uint8_t>>(
static_cast<int32_t>(ash::kShellWindowId_OverlayContainer));
......@@ -138,7 +113,9 @@ void TouchHudApplication::CreateWidgetForDisplay(int64_t display_id) {
params.name = "TouchHud";
widget->Init(params);
widget->Show();
display_id_to_widget_[display_id] = std::move(widget);
display_id_to_renderer_[display_id] =
std::make_unique<TouchHudRenderer>(std::move(widget));
}
void TouchHudApplication::Create(mash::mojom::LaunchableRequest request) {
......
......@@ -16,18 +16,21 @@
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
#include "ui/display/display_observer.h"
#include "ui/views/pointer_watcher.h"
namespace views {
class AuraInit;
class Widget;
} // namespace views
namespace touch_hud {
class TouchHudRenderer;
// Application that paints touch tap points as circles. Creates a fullscreen
// transparent widget on each display to draw the taps.
class TouchHudApplication : public service_manager::Service,
public mash::mojom::Launchable,
public views::PointerWatcher,
public display::DisplayObserver {
public:
TouchHudApplication();
......@@ -45,6 +48,11 @@ class TouchHudApplication : public service_manager::Service,
// mojom::Launchable:
void Launch(uint32_t what, mash::mojom::LaunchMode how) override;
// views::PointerWatcher:
void OnPointerEventObserved(const ui::PointerEvent& event,
const gfx::Point& location_in_screen,
gfx::NativeView target) override;
// display::DisplayObserver:
void OnDisplayAdded(const display::Display& new_display) override;
void OnDisplayRemoved(const display::Display& old_display) override;
......@@ -57,8 +65,8 @@ class TouchHudApplication : public service_manager::Service,
service_manager::BinderRegistry registry_;
mojo::Binding<mash::mojom::Launchable> binding_;
// Maps display::Display::id() to the touch HUD widget for that display.
std::map<int64_t, std::unique_ptr<views::Widget>> display_id_to_widget_;
// Maps display::Display::id() to the renderer for that display.
std::map<int64_t, std::unique_ptr<TouchHudRenderer>> display_id_to_renderer_;
std::unique_ptr<views::AuraInit> aura_init_;
......
// Copyright 2013 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/components/touch_hud/touch_hud_renderer.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_owner.h"
#include "ui/events/event.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
namespace touch_hud {
const int kPointRadius = 20;
const SkColor kProjectionFillColor = SkColorSetRGB(0xF5, 0xF5, 0xDC);
const SkColor kProjectionStrokeColor = SK_ColorGRAY;
const int kProjectionAlpha = 0xB0;
constexpr base::TimeDelta kFadeoutDuration =
base::TimeDelta::FromMilliseconds(250);
const int kFadeoutFrameRate = 60;
// TouchPointView draws a single touch point. Owned by the views hierarchy.
// Deletes itself upon fade-out completion.
class TouchPointView : public views::View, public gfx::AnimationDelegate {
public:
TouchPointView()
: circle_center_(kPointRadius + 1, kPointRadius + 1),
gradient_center_(SkPoint::Make(kPointRadius + 1, kPointRadius + 1)) {
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
SetSize(gfx::Size(2 * kPointRadius + 2, 2 * kPointRadius + 2));
stroke_flags_.setStyle(cc::PaintFlags::kStroke_Style);
stroke_flags_.setColor(kProjectionStrokeColor);
gradient_colors_[0] = kProjectionFillColor;
gradient_colors_[1] = kProjectionStrokeColor;
gradient_pos_[0] = SkFloatToScalar(0.9f);
gradient_pos_[1] = SkFloatToScalar(1.0f);
}
void UpdateTouch(const ui::PointerEvent& touch) {
if (touch.type() == ui::ET_POINTER_UP ||
touch.type() == ui::ET_POINTER_CANCELLED) {
fadeout_.reset(
new gfx::LinearAnimation(kFadeoutDuration, kFadeoutFrameRate, this));
fadeout_->Start();
} else {
SetX(parent()->GetMirroredXInView(touch.root_location().x()) -
kPointRadius - 1);
SetY(touch.root_location().y() - kPointRadius - 1);
}
}
// Destroys the view, which removes it from its parent.
void Destroy() { delete this; }
private:
~TouchPointView() override = default;
// Overridden from views::View.
void OnPaint(gfx::Canvas* canvas) override {
int alpha = kProjectionAlpha;
if (fadeout_)
alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0));
fill_flags_.setAlpha(alpha);
stroke_flags_.setAlpha(alpha);
fill_flags_.setShader(cc::PaintShader::MakeRadialGradient(
gradient_center_, SkIntToScalar(kPointRadius), gradient_colors_,
gradient_pos_, arraysize(gradient_colors_),
SkShader::kMirror_TileMode));
canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius),
fill_flags_);
canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius),
stroke_flags_);
}
// Overridden from gfx::AnimationDelegate.
void AnimationEnded(const gfx::Animation* animation) override {
DCHECK_EQ(fadeout_.get(), animation);
delete this;
}
void AnimationProgressed(const gfx::Animation* animation) override {
DCHECK_EQ(fadeout_.get(), animation);
SchedulePaint();
}
void AnimationCanceled(const gfx::Animation* animation) override {
AnimationEnded(animation);
}
const gfx::Point circle_center_;
const SkPoint gradient_center_;
cc::PaintFlags fill_flags_;
cc::PaintFlags stroke_flags_;
SkColor gradient_colors_[2];
SkScalar gradient_pos_[2];
std::unique_ptr<gfx::Animation> fadeout_;
DISALLOW_COPY_AND_ASSIGN(TouchPointView);
};
TouchHudRenderer::TouchHudRenderer(std::unique_ptr<views::Widget> widget)
: widget_(std::move(widget)) {
DCHECK(widget_);
}
TouchHudRenderer::~TouchHudRenderer() = default;
void TouchHudRenderer::HandleTouchEvent(const ui::PointerEvent& event) {
DCHECK(event.IsTouchPointerEvent());
const int id = event.pointer_details().id;
if (event.type() == ui::ET_POINTER_DOWN) {
TouchPointView* point = new TouchPointView();
widget_->GetContentsView()->AddChildView(point);
point->UpdateTouch(event);
std::pair<std::map<int, TouchPointView*>::iterator, bool> result =
points_.insert(std::make_pair(id, point));
// If a |TouchPointView| is already mapped to the touch id, destroy it and
// replace it with the new one.
if (!result.second) {
result.first->second->Destroy();
result.first->second = point;
}
} else {
std::map<int, TouchPointView*>::iterator iter = points_.find(id);
if (iter != points_.end()) {
iter->second->UpdateTouch(event);
if (event.type() == ui::ET_POINTER_UP ||
event.type() == ui::ET_POINTER_CANCELLED) {
points_.erase(iter);
// View will fade out then delete itself.
}
}
}
}
} // namespace touch_hud
// 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.
#ifndef ASH_COMPONENTS_TOUCH_HUD_TOUCH_HUD_RENDERER_H_
#define ASH_COMPONENTS_TOUCH_HUD_TOUCH_HUD_RENDERER_H_
#include <map>
#include <memory>
#include "base/macros.h"
namespace ui {
class PointerEvent;
}
namespace views {
class Widget;
}
namespace touch_hud {
class TouchPointView;
// Renders touch points into a widget.
class TouchHudRenderer {
public:
explicit TouchHudRenderer(std::unique_ptr<views::Widget> widget);
~TouchHudRenderer();
// Receives a touch event and draws its touch point.
void HandleTouchEvent(const ui::PointerEvent& event);
private:
// The widget containing the touch point views.
std::unique_ptr<views::Widget> widget_;
// A map of touch ids to TouchPointView.
std::map<int, TouchPointView*> points_;
DISALLOW_COPY_AND_ASSIGN(TouchHudRenderer);
};
} // namespace touch_hud
#endif // ASH_COMPONENTS_TOUCH_HUD_TOUCH_HUD_RENDERER_H_
......@@ -23,6 +23,8 @@ class TouchHudProjectionTest;
class TouchPointView;
// Handles touch events to draw out touch points accordingly.
// TODO(jamescook): Delete this when the mojo touch_hud_app is the default.
// https://crbug.com/840380
class ASH_TOUCH_HUD_EXPORT TouchHudRenderer {
public:
explicit TouchHudRenderer(views::Widget* parent_widget);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment