diff options
author | mohsen@chromium.org <mohsen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-01 22:43:40 +0000 |
---|---|---|
committer | mohsen@chromium.org <mohsen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-01 22:43:40 +0000 |
commit | 2b8a9bb937870c2274d091e29be7762ce1049b6b (patch) | |
tree | aba4c2e2235445df8e25c2dec9d8224adea6f8c6 /ash | |
parent | 18ee9f9651d653c8f983e5f3929293bd0265f3ea (diff) | |
download | chromium_src-2b8a9bb937870c2274d091e29be7762ce1049b6b.zip chromium_src-2b8a9bb937870c2274d091e29be7762ce1049b6b.tar.gz chromium_src-2b8a9bb937870c2274d091e29be7762ce1049b6b.tar.bz2 |
Separate projection mode from rest of touch HUD
Projection mode is separated from the rest of the touch HUD. It now can
be toggled on/off using Ctrl+Alt+9 key combination and no command line
flag is needed. The rest of the touch HUD is still behind the
--ash-touch-log flag.
BUG=233567
Review URL: https://chromiumcodereview.appspot.com/17063013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209523 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/accelerators/accelerator_controller.cc | 15 | ||||
-rw-r--r-- | ash/accelerators/accelerator_table.cc | 2 | ||||
-rw-r--r-- | ash/accelerators/accelerator_table.h | 1 | ||||
-rw-r--r-- | ash/ash.gyp | 4 | ||||
-rw-r--r-- | ash/root_window_controller.cc | 32 | ||||
-rw-r--r-- | ash/root_window_controller.h | 43 | ||||
-rw-r--r-- | ash/shell.cc | 20 | ||||
-rw-r--r-- | ash/shell.h | 8 | ||||
-rw-r--r-- | ash/touch/touch_hud_debug.cc | 491 | ||||
-rw-r--r-- | ash/touch/touch_hud_debug.h | 87 | ||||
-rw-r--r-- | ash/touch/touch_hud_projection.cc | 186 | ||||
-rw-r--r-- | ash/touch/touch_hud_projection.h | 44 | ||||
-rw-r--r-- | ash/touch/touch_observer_hud.cc | 606 | ||||
-rw-r--r-- | ash/touch/touch_observer_hud.h | 82 | ||||
-rw-r--r-- | ash/touch/touch_observer_hud_unittest.cc | 10 |
15 files changed, 948 insertions, 683 deletions
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc index b3e2b8d..b96c201 100644 --- a/ash/accelerators/accelerator_controller.cc +++ b/ash/accelerators/accelerator_controller.cc @@ -39,7 +39,7 @@ #include "ash/system/tray/system_tray_delegate.h" #include "ash/system/tray/system_tray_notifier.h" #include "ash/system/web_notification/web_notification_tray.h" -#include "ash/touch/touch_observer_hud.h" +#include "ash/touch/touch_hud_debug.h" #include "ash/volume_control_delegate.h" #include "ash/wm/partial_screenshot_view.h" #include "ash/wm/power_button_controller.h" @@ -561,8 +561,8 @@ bool AcceleratorController::PerformAction(int action, case TOUCH_HUD_CLEAR: { internal::RootWindowController* controller = internal::RootWindowController::ForActiveRootWindow(); - if (controller->touch_observer_hud()) { - controller->touch_observer_hud()->Clear(); + if (controller->touch_hud_debug()) { + controller->touch_hud_debug()->Clear(); return true; } return false; @@ -570,12 +570,17 @@ bool AcceleratorController::PerformAction(int action, case TOUCH_HUD_MODE_CHANGE: { internal::RootWindowController* controller = internal::RootWindowController::ForActiveRootWindow(); - if (controller->touch_observer_hud()) { - controller->touch_observer_hud()->ChangeToNextMode(); + if (controller->touch_hud_debug()) { + controller->touch_hud_debug()->ChangeToNextMode(); return true; } return false; } + case TOUCH_HUD_PROJECTION_TOGGLE: { + bool enabled = Shell::GetInstance()->is_touch_hud_projection_enabled(); + Shell::GetInstance()->SetTouchHudProjectionEnabled(!enabled); + return true; + } case DISABLE_GPU_WATCHDOG: content::GpuDataManager::GetInstance()->DisableGpuWatchdog(); return true; diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc index 6e7af10..5bfc38a 100644 --- a/ash/accelerators/accelerator_table.cc +++ b/ash/accelerators/accelerator_table.cc @@ -74,6 +74,8 @@ const AcceleratorData kAcceleratorData[] = { TOUCH_HUD_MODE_CHANGE }, { true, ui::VKEY_I, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN, TOUCH_HUD_CLEAR }, + { true, ui::VKEY_9, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + TOUCH_HUD_PROJECTION_TOGGLE }, // Accessibility: Spoken feedback shortcuts. The first one is to toggle // spoken feedback on or off. The others are only valid when // spoken feedback is enabled. diff --git a/ash/accelerators/accelerator_table.h b/ash/accelerators/accelerator_table.h index 277baaf..8c400ce 100644 --- a/ash/accelerators/accelerator_table.h +++ b/ash/accelerators/accelerator_table.h @@ -89,6 +89,7 @@ enum AcceleratorAction { TOGGLE_WIFI, TOUCH_HUD_CLEAR, TOUCH_HUD_MODE_CHANGE, + TOUCH_HUD_PROJECTION_TOGGLE, VOLUME_DOWN, VOLUME_MUTE, VOLUME_UP, diff --git a/ash/ash.gyp b/ash/ash.gyp index be6c931..0082676 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -347,6 +347,10 @@ 'system/user/user_observer.h', 'system/web_notification/web_notification_tray.cc', 'system/web_notification/web_notification_tray.h', + 'touch/touch_hud_debug.cc', + 'touch/touch_hud_debug.h', + 'touch/touch_hud_projection.cc', + 'touch/touch_hud_projection.h', 'touch/touch_observer_hud.cc', 'touch/touch_observer_hud.h', 'touch/touch_uma.cc', diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 2ce0102..b765fff 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc @@ -21,7 +21,8 @@ #include "ash/shell_window_ids.h" #include "ash/system/status_area_widget.h" #include "ash/system/tray/system_tray_delegate.h" -#include "ash/touch/touch_observer_hud.h" +#include "ash/touch/touch_hud_debug.h" +#include "ash/touch/touch_hud_projection.h" #include "ash/wm/base_layout_manager.h" #include "ash/wm/boot_splash_screen.h" #include "ash/wm/dock/docked_window_layout_manager.h" @@ -169,7 +170,8 @@ RootWindowController::RootWindowController(aura::RootWindow* root_window) root_window_layout_(NULL), docked_layout_manager_(NULL), panel_layout_manager_(NULL), - touch_observer_hud_(NULL) { + touch_hud_debug_(NULL), + touch_hud_projection_(NULL) { SetRootWindowController(root_window, this); screen_dimmer_.reset(new ScreenDimmer(root_window)); @@ -303,12 +305,6 @@ void RootWindowController::InitForPrimaryDisplay() { void RootWindowController::CreateContainers() { CreateContainersInRootWindow(root_window_.get()); - - // Create touch observer HUD if needed. HUD should be created after the - // containers have been created, so that its widget can be added to them. - CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kAshTouchHud)) - touch_observer_hud_ = new TouchObserverHUD(root_window_.get()); } void RootWindowController::CreateSystemBackground( @@ -414,6 +410,18 @@ void RootWindowController::MoveWindowsTo(aura::RootWindow* dst) { ReparentAllWindows(root_window_.get(), dst); } +void RootWindowController::EnableTouchHudProjection() { + if (touch_hud_projection_) + return; + set_touch_hud_projection(new TouchHudProjection(root_window_.get())); +} + +void RootWindowController::DisableTouchHudProjection() { + if (!touch_hud_projection_) + return; + touch_hud_projection_->Remove(); +} + ShelfLayoutManager* RootWindowController::GetShelfLayoutManager() { return shelf_.get() ? shelf_->shelf_layout_manager() : NULL; } @@ -456,6 +464,14 @@ void RootWindowController::UpdateShelfVisibility() { shelf_->shelf_layout_manager()->UpdateVisibilityState(); } +void RootWindowController::InitTouchHuds() { + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kAshTouchHud)) + set_touch_hud_debug(new TouchHudDebug(root_window_.get())); + if (Shell::GetInstance()->is_touch_hud_projection_enabled()) + EnableTouchHudProjection(); +} + aura::Window* RootWindowController::GetFullscreenWindow() const { aura::Window* container = workspace_controller_->GetActiveWorkspaceWindow(); for (size_t i = 0; i < container->children().size(); ++i) { diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 2c02b20..4fe4578 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h @@ -5,6 +5,8 @@ #ifndef ASH_ROOT_WINDOW_CONTROLLER_H_ #define ASH_ROOT_WINDOW_CONTROLLER_H_ +#include <map> + #include "ash/ash_export.h" #include "ash/shelf/shelf_types.h" #include "ash/system/user/login_status.h" @@ -52,7 +54,8 @@ class ShelfLayoutManager; class StatusAreaWidget; class SystemBackgroundController; class SystemModalContainerLayoutManager; -class TouchObserverHUD; +class TouchHudDebug; +class TouchHudProjection; class WorkspaceController; // This class maintains the per root window state for ash. This class @@ -91,13 +94,31 @@ class ASH_EXPORT RootWindowController { // NULL if no such shelf exists. ShelfWidget* shelf() { return shelf_.get(); } - TouchObserverHUD* touch_observer_hud() { return touch_observer_hud_; } + // Get touch HUDs associated with this root window controller. + TouchHudDebug* touch_hud_debug() const { + return touch_hud_debug_; + } + TouchHudProjection* touch_hud_projection() const { + return touch_hud_projection_; + } - // Sets the touch HUD. The RootWindowController will not own this HUD; its - // lifetime is managed by itself. - void set_touch_observer_hud(TouchObserverHUD* hud) { - touch_observer_hud_ = hud; + // Set touch HUDs for this root window controller. The root window controller + // will not own the HUDs; their lifetimes are managed by themselves. Whenever + // the widget showing a HUD is being destroyed (e.g. because of detaching a + // display), the HUD deletes itself. + void set_touch_hud_debug(TouchHudDebug* hud) { + touch_hud_debug_ = hud; + } + void set_touch_hud_projection(TouchHudProjection* hud) { + touch_hud_projection_ = hud; } + + // Enables projection touch HUD. + void EnableTouchHudProjection(); + + // Disables projection touch HUD. + void DisableTouchHudProjection(); + // Access the shelf layout manager associated with this root // window controller, NULL if no such shelf exists. ShelfLayoutManager* GetShelfLayoutManager(); @@ -172,6 +193,9 @@ class ASH_EXPORT RootWindowController { // Force the shelf to query for it's current visibility state. void UpdateShelfVisibility(); + // Initialize touch HUDs if necessary. + void InitTouchHuds(); + // Returns the window, if any, which is in fullscreen mode in the active // workspace. Exposed here so clients of Ash don't need to know the details // of workspace management. @@ -207,9 +231,10 @@ class ASH_EXPORT RootWindowController { scoped_ptr<ScreenDimmer> screen_dimmer_; scoped_ptr<WorkspaceController> workspace_controller_; - // Heads-up display for touch events. The RootWindowController does not own - // this HUD; its lifetime is managed by itself. - TouchObserverHUD* touch_observer_hud_; + // Heads-up displays for touch events. These HUDs are not owned by the root + // window controller and manage their own lifetimes. + TouchHudDebug* touch_hud_debug_; + TouchHudProjection* touch_hud_projection_; // We need to own event handlers for various containers. scoped_ptr<ToplevelWindowEventHandler> default_container_handler_; diff --git a/ash/shell.cc b/ash/shell.cc index cfd3105..0ee5b6f 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -211,7 +211,8 @@ Shell::Shell(ShellDelegate* delegate) cursor_manager_(scoped_ptr<views::corewm::NativeCursorManager>( native_cursor_manager_)), browser_context_(NULL), - simulate_modal_window_open_for_testing_(false) { + simulate_modal_window_open_for_testing_(false), + is_touch_hud_projection_enabled_(false) { DCHECK(delegate_.get()); display_manager_.reset(new internal::DisplayManager); mirror_window_controller_.reset(new internal::MirrorWindowController); @@ -860,6 +861,22 @@ LauncherDelegate* Shell::GetLauncherDelegate() { return launcher_delegate_.get(); } +void Shell::SetTouchHudProjectionEnabled(bool enabled) { + if (is_touch_hud_projection_enabled_ == enabled) + return; + + RootWindowList roots = GetInstance()->GetAllRootWindows(); + for (RootWindowList::iterator iter = roots.begin(); iter != roots.end(); + ++iter) { + internal::RootWindowController* controller = GetRootWindowController(*iter); + if (enabled) + controller->EnableTouchHudProjection(); + else + controller->DisableTouchHudProjection(); + } + is_touch_hud_projection_enabled_ = enabled; +} + void Shell::InitRootWindowForSecondaryDisplay(aura::RootWindow* root) { aura::client::SetFocusClient(root, focus_client_.get()); internal::RootWindowController* controller = @@ -919,6 +936,7 @@ void Shell::InitRootWindowController( root_window->SetCursor(ui::kCursorPointer); controller->InitLayoutManagers(); + controller->InitTouchHuds(); // TODO(oshima): Move the instance to RootWindowController when // the extended desktop is enabled by default. diff --git a/ash/shell.h b/ash/shell.h index f8649dc..62ef0ff 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -462,6 +462,12 @@ class ASH_EXPORT Shell // Returns the launcher delegate, creating if necesary. LauncherDelegate* GetLauncherDelegate(); + void SetTouchHudProjectionEnabled(bool enabled); + + bool is_touch_hud_projection_enabled() const { + return is_touch_hud_projection_enabled_; + } + private: FRIEND_TEST_ALL_PREFIXES(ExtendedDesktopTest, TestCursor); FRIEND_TEST_ALL_PREFIXES(WindowManagerTest, MouseEventCursors); @@ -604,6 +610,8 @@ class ASH_EXPORT Shell // For testing only: simulate that a modal window is open bool simulate_modal_window_open_for_testing_; + bool is_touch_hud_projection_enabled_; + DISALLOW_COPY_AND_ASSIGN(Shell); }; diff --git a/ash/touch/touch_hud_debug.cc b/ash/touch/touch_hud_debug.cc new file mode 100644 index 0000000..5b7c120 --- /dev/null +++ b/ash/touch/touch_hud_debug.cc @@ -0,0 +1,491 @@ +// 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/touch/touch_hud_debug.h" + +#include "ash/display/display_manager.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ash/wm/property_util.h" +#include "base/json/json_string_value_serializer.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "third_party/skia/include/core/SkPath.h" +#include "ui/aura/root_window.h" +#include "ui/base/animation/animation_delegate.h" +#include "ui/base/events/event.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/display.h" +#include "ui/gfx/size.h" +#include "ui/gfx/transform.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/widget/widget.h" + +#if defined(USE_X11) +#include <X11/extensions/XInput2.h> +#include <X11/Xlib.h> + +#include "ui/base/x/device_data_manager.h" +#endif + +namespace ash { +namespace internal { + +const int kPointRadius = 20; +const SkColor kColors[] = { + SK_ColorYELLOW, + SK_ColorGREEN, + SK_ColorRED, + SK_ColorBLUE, + SK_ColorGRAY, + SK_ColorMAGENTA, + SK_ColorCYAN, + SK_ColorWHITE, + SK_ColorBLACK, + SkColorSetRGB(0xFF, 0x8C, 0x00), + SkColorSetRGB(0x8B, 0x45, 0x13), + SkColorSetRGB(0xFF, 0xDE, 0xAD), +}; +const int kAlpha = 0x60; +const int kMaxPaths = arraysize(kColors); +const int kReducedScale = 10; + +const char* GetTouchEventLabel(ui::EventType type) { + switch (type) { + case ui::ET_UNKNOWN: + return " "; + case ui::ET_TOUCH_PRESSED: + return "P"; + case ui::ET_TOUCH_MOVED: + return "M"; + case ui::ET_TOUCH_RELEASED: + return "R"; + case ui::ET_TOUCH_CANCELLED: + return "C"; + default: + break; + } + return "?"; +} + +int GetTrackingId(const ui::TouchEvent& event) { + if (!event.HasNativeEvent()) + return 0; +#if defined(USE_XI2_MT) + ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); + double tracking_id; + if (manager->GetEventData(*event.native_event(), + ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, + &tracking_id)) { + return static_cast<int>(tracking_id); + } +#endif + return 0; +} + +int GetSourceDeviceId(const ui::TouchEvent& event) { + if (!event.HasNativeEvent()) + return 0; +#if defined(USE_X11) + XEvent* xev = event.native_event(); + return static_cast<XIDeviceEvent*>(xev->xcookie.data)->sourceid; +#endif + return 0; +} + +// A TouchPointLog represents a single touch-event of a touch point. +struct TouchPointLog { + public: + explicit TouchPointLog(const ui::TouchEvent& touch) + : id(touch.touch_id()), + type(touch.type()), + location(touch.root_location()), + timestamp(touch.time_stamp().InMillisecondsF()), + radius_x(touch.radius_x()), + radius_y(touch.radius_y()), + pressure(touch.force()), + tracking_id(GetTrackingId(touch)), + source_device(GetSourceDeviceId(touch)) { + } + + // Populates a dictionary value with all the information about the touch + // point. + scoped_ptr<DictionaryValue> GetAsDictionary() const { + scoped_ptr<DictionaryValue> value(new DictionaryValue()); + + value->SetInteger("id", id); + value->SetString("type", std::string(GetTouchEventLabel(type))); + value->SetString("location", location.ToString()); + value->SetDouble("timestamp", timestamp); + value->SetDouble("radius_x", radius_x); + value->SetDouble("radius_y", radius_y); + value->SetDouble("pressure", pressure); + value->SetInteger("tracking_id", tracking_id); + value->SetInteger("source_device", source_device); + + return value.Pass(); + } + + int id; + ui::EventType type; + gfx::Point location; + double timestamp; + float radius_x; + float radius_y; + float pressure; + int tracking_id; + int source_device; +}; + +// A TouchTrace keeps track of all the touch events of a single touch point +// (starting from a touch-press and ending at a touch-release or touch-cancel). +class TouchTrace { + public: + typedef std::vector<TouchPointLog>::iterator iterator; + typedef std::vector<TouchPointLog>::const_iterator const_iterator; + typedef std::vector<TouchPointLog>::reverse_iterator reverse_iterator; + typedef std::vector<TouchPointLog>::const_reverse_iterator + const_reverse_iterator; + + TouchTrace() { + } + + void AddTouchPoint(const ui::TouchEvent& touch) { + log_.push_back(TouchPointLog(touch)); + } + + const std::vector<TouchPointLog>& log() const { return log_; } + + bool active() const { + return !log_.empty() && log_.back().type != ui::ET_TOUCH_RELEASED && + log_.back().type != ui::ET_TOUCH_CANCELLED; + } + + // Returns a list containing data from all events for the touch point. + scoped_ptr<ListValue> GetAsList() const { + scoped_ptr<ListValue> list(new ListValue()); + for (const_iterator i = log_.begin(); i != log_.end(); ++i) + list->Append((*i).GetAsDictionary().release()); + return list.Pass(); + } + + void Reset() { + log_.clear(); + } + + private: + std::vector<TouchPointLog> log_; + + DISALLOW_COPY_AND_ASSIGN(TouchTrace); +}; + +// A TouchLog keeps track of all touch events of all touch points. +class TouchLog { + public: + TouchLog() : next_trace_index_(0) { + } + + void AddTouchPoint(const ui::TouchEvent& touch) { + if (touch.type() == ui::ET_TOUCH_PRESSED) + StartTrace(touch); + AddToTrace(touch); + } + + void Reset() { + next_trace_index_ = 0; + for (int i = 0; i < kMaxPaths; ++i) + traces_[i].Reset(); + } + + scoped_ptr<ListValue> GetAsList() const { + scoped_ptr<ListValue> list(new ListValue()); + for (int i = 0; i < kMaxPaths; ++i) { + if (!traces_[i].log().empty()) + list->Append(traces_[i].GetAsList().release()); + } + return list.Pass(); + } + + int GetTraceIndex(int touch_id) const { + return touch_id_to_trace_index_.at(touch_id); + } + + const TouchTrace* traces() const { + return traces_; + } + + private: + void StartTrace(const ui::TouchEvent& touch) { + // Find the first inactive spot; otherwise, overwrite the one + // |next_trace_index_| is pointing to. + int old_trace_index = next_trace_index_; + do { + if (!traces_[next_trace_index_].active()) + break; + next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; + } while (next_trace_index_ != old_trace_index); + int touch_id = touch.touch_id(); + traces_[next_trace_index_].Reset(); + touch_id_to_trace_index_[touch_id] = next_trace_index_; + next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; + } + + void AddToTrace(const ui::TouchEvent& touch) { + int touch_id = touch.touch_id(); + int trace_index = touch_id_to_trace_index_[touch_id]; + traces_[trace_index].AddTouchPoint(touch); + } + + TouchTrace traces_[kMaxPaths]; + int next_trace_index_; + + std::map<int, int> touch_id_to_trace_index_; + + DISALLOW_COPY_AND_ASSIGN(TouchLog); +}; + +// TouchHudCanvas draws touch traces in |FULLSCREEN| and |REDUCED_SCALE| modes. +class TouchHudCanvas : public views::View { + public: + explicit TouchHudCanvas(const TouchLog& touch_log) + : touch_log_(touch_log), + scale_(1) { + SetPaintToLayer(true); + SetFillsBoundsOpaquely(false); + + paint_.setStyle(SkPaint::kFill_Style); + } + + virtual ~TouchHudCanvas() {} + + void SetScale(int scale) { + if (scale_ == scale) + return; + scale_ = scale; + gfx::Transform transform; + transform.Scale(1. / scale_, 1. / scale_); + layer()->SetTransform(transform); + } + + int scale() const { return scale_; } + + void TouchPointAdded(int touch_id) { + int trace_index = touch_log_.GetTraceIndex(touch_id); + const TouchTrace& trace = touch_log_.traces()[trace_index]; + const TouchPointLog& point = trace.log().back(); + if (point.type == ui::ET_TOUCH_PRESSED) + StartedTrace(trace_index); + if (point.type != ui::ET_TOUCH_CANCELLED) + AddedPointToTrace(trace_index); + } + + void Clear() { + for (int i = 0; i < kMaxPaths; ++i) + paths_[i].reset(); + + SchedulePaint(); + } + + private: + void StartedTrace(int trace_index) { + paths_[trace_index].reset(); + colors_[trace_index] = SkColorSetA(kColors[trace_index], kAlpha); + } + + void AddedPointToTrace(int trace_index) { + const TouchTrace& trace = touch_log_.traces()[trace_index]; + const TouchPointLog& point = trace.log().back(); + const gfx::Point& location = point.location; + SkScalar x = SkIntToScalar(location.x()); + SkScalar y = SkIntToScalar(location.y()); + SkPoint last; + if (!paths_[trace_index].getLastPt(&last) || x != last.x() || + y != last.y()) { + paths_[trace_index].addCircle(x, y, SkIntToScalar(kPointRadius)); + SchedulePaint(); + } + } + + // Overridden from views::View. + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + for (int i = 0; i < kMaxPaths; ++i) { + if (paths_[i].countPoints() == 0) + continue; + paint_.setColor(colors_[i]); + canvas->DrawPath(paths_[i], paint_); + } + } + + SkPaint paint_; + + const TouchLog& touch_log_; + SkPath paths_[kMaxPaths]; + SkColor colors_[kMaxPaths]; + + int scale_; + + DISALLOW_COPY_AND_ASSIGN(TouchHudCanvas); +}; + +TouchHudDebug::TouchHudDebug(aura::RootWindow* initial_root) + : TouchObserverHUD(initial_root), + mode_(FULLSCREEN), + touch_log_(new TouchLog()), + canvas_(NULL), + label_container_(NULL) { + const gfx::Display& display = + Shell::GetInstance()->display_manager()->GetDisplayForId(display_id()); + + views::View* content = widget()->GetContentsView(); + + canvas_ = new TouchHudCanvas(*touch_log_); + content->AddChildView(canvas_); + + const gfx::Size& display_size = display.size(); + canvas_->SetSize(display_size); + + label_container_ = new views::View; + label_container_->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kVertical, 0, 0, 0)); + + for (int i = 0; i < kMaxTouchPoints; ++i) { + touch_labels_[i] = new views::Label; + touch_labels_[i]->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255)); + touch_labels_[i]->SetShadowColors(SK_ColorWHITE, + SK_ColorWHITE); + touch_labels_[i]->SetShadowOffset(1, 1); + label_container_->AddChildView(touch_labels_[i]); + } + label_container_->SetX(0); + label_container_->SetY(display_size.height() / kReducedScale); + label_container_->SetSize(label_container_->GetPreferredSize()); + label_container_->SetVisible(false); + content->AddChildView(label_container_); +} + +TouchHudDebug::~TouchHudDebug() { +} + +// static +scoped_ptr<DictionaryValue> TouchHudDebug::GetAllAsDictionary() { + scoped_ptr<DictionaryValue> value(new DictionaryValue()); + Shell::RootWindowList roots = Shell::GetInstance()->GetAllRootWindows(); + for (Shell::RootWindowList::iterator iter = roots.begin(); + iter != roots.end(); ++iter) { + internal::RootWindowController* controller = GetRootWindowController(*iter); + internal::TouchHudDebug* hud = controller->touch_hud_debug(); + if (hud) { + scoped_ptr<ListValue> list = hud->GetLogAsList(); + if (!list->empty()) + value->Set(base::Int64ToString(hud->display_id()), list.release()); + } + } + return value.Pass(); +} + +void TouchHudDebug::ChangeToNextMode() { + switch (mode_) { + case FULLSCREEN: + SetMode(REDUCED_SCALE); + break; + case REDUCED_SCALE: + SetMode(INVISIBLE); + break; + case INVISIBLE: + SetMode(FULLSCREEN); + break; + } +} + +scoped_ptr<ListValue> TouchHudDebug::GetLogAsList() const { + return touch_log_->GetAsList(); +} + +void TouchHudDebug::Clear() { + if (widget()->IsVisible()) { + canvas_->Clear(); + for (int i = 0; i < kMaxTouchPoints; ++i) + touch_labels_[i]->SetText(string16()); + label_container_->SetSize(label_container_->GetPreferredSize()); + } +} + +void TouchHudDebug::SetMode(Mode mode) { + if (mode_ == mode) + return; + mode_ = mode; + switch (mode) { + case FULLSCREEN: + label_container_->SetVisible(false); + canvas_->SetVisible(true); + canvas_->SetScale(1); + canvas_->SchedulePaint(); + widget()->Show(); + break; + case REDUCED_SCALE: + label_container_->SetVisible(true); + canvas_->SetVisible(true); + canvas_->SetScale(kReducedScale); + canvas_->SchedulePaint(); + widget()->Show(); + break; + case INVISIBLE: + widget()->Hide(); + break; + } +} + +void TouchHudDebug::UpdateTouchPointLabel(int index) { + int trace_index = touch_log_->GetTraceIndex(index); + const TouchTrace& trace = touch_log_->traces()[trace_index]; + TouchTrace::const_reverse_iterator point = trace.log().rbegin(); + ui::EventType touch_status = point->type; + float touch_radius = std::max(point->radius_x, point->radius_y); + while (point != trace.log().rend() && point->type == ui::ET_TOUCH_CANCELLED) + point++; + DCHECK(point != trace.log().rend()); + gfx::Point touch_position = point->location; + + std::string string = base::StringPrintf("%2d: %s %s (%.4f)", + index, + GetTouchEventLabel(touch_status), + touch_position.ToString().c_str(), + touch_radius); + touch_labels_[index]->SetText(UTF8ToUTF16(string)); +} + +void TouchHudDebug::OnTouchEvent(ui::TouchEvent* event) { + if (event->touch_id() >= kMaxTouchPoints) + return; + + touch_log_->AddTouchPoint(*event); + canvas_->TouchPointAdded(event->touch_id()); + UpdateTouchPointLabel(event->touch_id()); + label_container_->SetSize(label_container_->GetPreferredSize()); +} + +void TouchHudDebug::OnDisplayBoundsChanged(const gfx::Display& display) { + TouchObserverHUD::OnDisplayBoundsChanged(display); + + if (display.id() != display_id()) + return; + const gfx::Size& size = display.size(); + canvas_->SetSize(size); + label_container_->SetY(size.height() / kReducedScale); +} + +void TouchHudDebug::SetHudForRootWindowController( + RootWindowController* controller) { + controller->set_touch_hud_debug(this); +} + +void TouchHudDebug::UnsetHudForRootWindowController( + RootWindowController* controller) { + controller->set_touch_hud_debug(NULL); +} + +} // namespace internal +} // namespace ash diff --git a/ash/touch/touch_hud_debug.h b/ash/touch/touch_hud_debug.h new file mode 100644 index 0000000..a02a888 --- /dev/null +++ b/ash/touch/touch_hud_debug.h @@ -0,0 +1,87 @@ +// 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. + +#ifndef ASH_TOUCH_TOUCH_HUD_DEBUG_H_ +#define ASH_TOUCH_TOUCH_HUD_DEBUG_H_ + +#include <map> + +#include "ash/ash_export.h" +#include "ash/touch/touch_observer_hud.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" + +namespace views { +class Label; +class View; +} + +namespace ash { +namespace internal { + +class TouchHudCanvas; +class TouchLog; + +// A heads-up display to show touch traces on the screen and log touch events. +// As a derivative of TouchObserverHUD, objects of this class manage their own +// lifetime. +class ASH_EXPORT TouchHudDebug : public TouchObserverHUD { + public: + enum Mode { + FULLSCREEN, + REDUCED_SCALE, + INVISIBLE, + }; + + explicit TouchHudDebug(aura::RootWindow* initial_root); + + // Returns the log of touch events for all displays as a dictionary mapping id + // of each display to its touch log. + static scoped_ptr<DictionaryValue> GetAllAsDictionary(); + + // Changes the display mode (e.g. scale, visibility). Calling this repeatedly + // cycles between a fixed number of display modes. + void ChangeToNextMode(); + + // Returns log of touch events as a list value. Each item in the list is a + // trace of one touch point. + scoped_ptr<ListValue> GetLogAsList() const; + + Mode mode() const { return mode_; } + + // Overriden from TouchObserverHUD. + virtual void Clear() OVERRIDE; + + private: + virtual ~TouchHudDebug(); + + void SetMode(Mode mode); + + void UpdateTouchPointLabel(int index); + + // Overriden from TouchObserverHUD. + virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE; + virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE; + virtual void SetHudForRootWindowController( + RootWindowController* controller) OVERRIDE; + virtual void UnsetHudForRootWindowController( + RootWindowController* controller) OVERRIDE; + + static const int kMaxTouchPoints = 32; + + Mode mode_; + + scoped_ptr<TouchLog> touch_log_; + + TouchHudCanvas* canvas_; + views::View* label_container_; + views::Label* touch_labels_[kMaxTouchPoints]; + + DISALLOW_COPY_AND_ASSIGN(TouchHudDebug); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_TOUCH_TOUCH_HUD_DEBUG_H_ diff --git a/ash/touch/touch_hud_projection.cc b/ash/touch/touch_hud_projection.cc new file mode 100644 index 0000000..3a834a5 --- /dev/null +++ b/ash/touch/touch_hud_projection.cc @@ -0,0 +1,186 @@ +// 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/touch/touch_hud_projection.h" + +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ash/wm/property_util.h" +#include "third_party/skia/include/effects/SkGradientShader.h" +#include "ui/base/animation/animation_delegate.h" +#include "ui/base/animation/linear_animation.h" +#include "ui/base/events/event.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/size.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace internal { + +const int kPointRadius = 20; +const SkColor kProjectionFillColor = SkColorSetRGB(0xF5, 0xF5, 0xDC); +const SkColor kProjectionStrokeColor = SK_ColorGRAY; +const int kProjectionAlpha = 0xB0; +const int kFadeoutDurationInMs = 250; +const int kFadeoutFrameRate = 60; + +// TouchPointView draws a single touch point. This object manages its own +// lifetime and deletes itself upon fade-out completion or whenever |Remove()| +// is explicitly called. +class TouchPointView : public views::View, + public ui::AnimationDelegate, + public views::WidgetObserver { + public: + explicit TouchPointView(views::Widget* parent_widget) + : circle_center_(kPointRadius + 1, kPointRadius + 1), + gradient_center_(SkPoint::Make(kPointRadius + 1, + kPointRadius + 1)) { + SetPaintToLayer(true); + SetFillsBoundsOpaquely(false); + + SetSize(gfx::Size(2 * kPointRadius + 2, 2 * kPointRadius + 2)); + + stroke_paint_.setStyle(SkPaint::kStroke_Style); + stroke_paint_.setColor(kProjectionStrokeColor); + + gradient_colors_[0] = kProjectionFillColor; + gradient_colors_[1] = kProjectionStrokeColor; + + gradient_pos_[0] = SkFloatToScalar(0.9f); + gradient_pos_[1] = SkFloatToScalar(1.0f); + + parent_widget->GetContentsView()->AddChildView(this); + + parent_widget->AddObserver(this); + } + + void UpdateTouch(const ui::TouchEvent& touch) { + if (touch.type() == ui::ET_TOUCH_RELEASED || + touch.type() == ui::ET_TOUCH_CANCELLED) { + fadeout_.reset(new ui::LinearAnimation(kFadeoutDurationInMs, + kFadeoutFrameRate, + this)); + fadeout_->Start(); + } else { + SetX(touch.root_location().x() - kPointRadius - 1); + SetY(touch.root_location().y() - kPointRadius - 1); + } + } + + void Remove() { + delete this; + } + + private: + virtual ~TouchPointView() { + GetWidget()->RemoveObserver(this); + parent()->RemoveChildView(this); + } + + // Overridden from views::View. + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + int alpha = kProjectionAlpha; + if (fadeout_) + alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0)); + fill_paint_.setAlpha(alpha); + stroke_paint_.setAlpha(alpha); + SkShader* shader = SkGradientShader::CreateRadial( + gradient_center_, + SkIntToScalar(kPointRadius), + gradient_colors_, + gradient_pos_, + arraysize(gradient_colors_), + SkShader::kMirror_TileMode, + NULL); + fill_paint_.setShader(shader); + shader->unref(); + canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), + fill_paint_); + canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), + stroke_paint_); + } + + // Overridden from ui::AnimationDelegate. + virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE { + DCHECK_EQ(fadeout_.get(), animation); + delete this; + } + + virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { + DCHECK_EQ(fadeout_.get(), animation); + SchedulePaint(); + } + + virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE { + AnimationEnded(animation); + } + + // Overridden from views::WidgetObserver. + virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE { + fadeout_->Stop(); + } + + const gfx::Point circle_center_; + const SkPoint gradient_center_; + + SkPaint fill_paint_; + SkPaint stroke_paint_; + SkColor gradient_colors_[2]; + SkScalar gradient_pos_[2]; + + scoped_ptr<ui::Animation> fadeout_; + + DISALLOW_COPY_AND_ASSIGN(TouchPointView); +}; + +TouchHudProjection::TouchHudProjection(aura::RootWindow* initial_root) + : TouchObserverHUD(initial_root) { +} + +TouchHudProjection::~TouchHudProjection() { +} + +void TouchHudProjection::Clear() { + for (std::map<int, TouchPointView*>::iterator iter = points_.begin(); + iter != points_.end(); iter++) + iter->second->Remove(); + points_.clear(); +} + +void TouchHudProjection::OnTouchEvent(ui::TouchEvent* event) { + if (event->type() == ui::ET_TOUCH_PRESSED) { + TouchPointView* point = new TouchPointView(widget()); + point->UpdateTouch(*event); + std::pair<std::map<int, TouchPointView*>::iterator, bool> result = + points_.insert(std::make_pair(event->touch_id(), point)); + // If a |TouchPointView| is already mapped to the touch id, remove it and + // replace it with the new one. + if (!result.second) { + result.first->second->Remove(); + result.first->second = point; + } + } else { + std::map<int, TouchPointView*>::iterator iter = + points_.find(event->touch_id()); + if (iter != points_.end()) { + iter->second->UpdateTouch(*event); + if (event->type() == ui::ET_TOUCH_RELEASED || + event->type() == ui::ET_TOUCH_CANCELLED) + points_.erase(iter); + } + } +} + +void TouchHudProjection::SetHudForRootWindowController( + RootWindowController* controller) { + controller->set_touch_hud_projection(this); +} + +void TouchHudProjection::UnsetHudForRootWindowController( + RootWindowController* controller) { + controller->set_touch_hud_projection(NULL); +} + +} // namespace internal +} // namespace ash diff --git a/ash/touch/touch_hud_projection.h b/ash/touch/touch_hud_projection.h new file mode 100644 index 0000000..29fddc3 --- /dev/null +++ b/ash/touch/touch_hud_projection.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef ASH_TOUCH_TOUCH_HUD_PROJECTION_H_ +#define ASH_TOUCH_TOUCH_HUD_PROJECTION_H_ + +#include <map> + +#include "ash/touch/touch_observer_hud.h" + +namespace ash { +namespace internal { + +class TouchPointView; + +// A heads-up display to show active touch points on the screen. As a derivative +// of TouchObserverHUD, objects of this class manage their own lifetime. +class TouchHudProjection : public TouchObserverHUD { + public: + explicit TouchHudProjection(aura::RootWindow* initial_root); + + // Overriden from TouchObserverHUD. + virtual void Clear() OVERRIDE; + + private: + virtual ~TouchHudProjection(); + + // Overriden from TouchObserverHUD. + virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE; + virtual void SetHudForRootWindowController( + RootWindowController* controller) OVERRIDE; + virtual void UnsetHudForRootWindowController( + RootWindowController* controller) OVERRIDE; + + std::map<int, TouchPointView*> points_; + + DISALLOW_COPY_AND_ASSIGN(TouchHudProjection); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_TOUCH_TOUCH_HUD_PROJECTION_H_ diff --git a/ash/touch/touch_observer_hud.cc b/ash/touch/touch_observer_hud.cc index 135da1a..ceb87fd 100644 --- a/ash/touch/touch_observer_hud.cc +++ b/ash/touch/touch_observer_hud.cc @@ -4,496 +4,40 @@ #include "ash/touch/touch_observer_hud.h" -#include "ash/display/display_controller.h" #include "ash/display/display_manager.h" #include "ash/root_window_controller.h" +#include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/wm/property_util.h" -#include "base/json/json_string_value_serializer.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "third_party/skia/include/core/SkPath.h" -#include "third_party/skia/include/core/SkXfermode.h" -#include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/aura/root_window.h" -#include "ui/aura/window.h" -#include "ui/base/animation/animation_delegate.h" -#include "ui/base/animation/linear_animation.h" -#include "ui/base/events/event.h" -#include "ui/gfx/canvas.h" #include "ui/gfx/display.h" #include "ui/gfx/rect.h" #include "ui/gfx/screen.h" #include "ui/gfx/size.h" -#include "ui/gfx/transform.h" -#include "ui/views/background.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" #include "ui/views/widget/widget.h" -#if defined(USE_X11) -#include <X11/extensions/XInput2.h> -#include <X11/Xlib.h> - -#include "ui/base/x/device_data_manager.h" -#endif - namespace ash { namespace internal { -const int kPointRadius = 20; -const SkColor kColors[] = { - SK_ColorYELLOW, - SK_ColorGREEN, - SK_ColorRED, - SK_ColorBLUE, - SK_ColorGRAY, - SK_ColorMAGENTA, - SK_ColorCYAN, - SK_ColorWHITE, - SK_ColorBLACK, - SkColorSetRGB(0xFF, 0x8C, 0x00), - SkColorSetRGB(0x8B, 0x45, 0x13), - SkColorSetRGB(0xFF, 0xDE, 0xAD), -}; -const int kAlpha = 0x60; -const SkColor kProjectionFillColor = SkColorSetRGB(0xF5, 0xF5, 0xDC); -const SkColor kProjectionStrokeColor = SK_ColorGRAY; -const int kProjectionAlpha = 0xB0; -const int kMaxPaths = arraysize(kColors); -const int kReducedScale = 10; -const int kFadeoutDurationInMs = 250; -const int kFadeoutFrameRate = 60; - -const char* GetTouchEventLabel(ui::EventType type) { - switch (type) { - case ui::ET_UNKNOWN: - return " "; - case ui::ET_TOUCH_PRESSED: - return "P"; - case ui::ET_TOUCH_MOVED: - return "M"; - case ui::ET_TOUCH_RELEASED: - return "R"; - case ui::ET_TOUCH_CANCELLED: - return "C"; - default: - break; - } - return "?"; -} - -int GetTrackingId(const ui::TouchEvent& event) { - if (!event.HasNativeEvent()) - return 0; -#if defined(USE_XI2_MT) - ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); - double tracking_id; - if (manager->GetEventData(*event.native_event(), - ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, - &tracking_id)) { - return static_cast<int>(tracking_id); - } -#endif - return 0; -} - -int GetSourceDeviceId(const ui::TouchEvent& event) { - if (!event.HasNativeEvent()) - return 0; -#if defined(USE_X11) - XEvent* xev = event.native_event(); - return static_cast<XIDeviceEvent*>(xev->xcookie.data)->sourceid; -#endif - return 0; -} - -// A TouchPointLog represents a single touch-event of a touch point. -struct TouchPointLog { - public: - explicit TouchPointLog(const ui::TouchEvent& touch) - : id(touch.touch_id()), - type(touch.type()), - location(touch.root_location()), - timestamp(touch.time_stamp().InMillisecondsF()), - radius_x(touch.radius_x()), - radius_y(touch.radius_y()), - pressure(touch.force()), - tracking_id(GetTrackingId(touch)), - source_device(GetSourceDeviceId(touch)) { - } - - // Populates a dictionary value with all the information about the touch - // point. - scoped_ptr<DictionaryValue> GetAsDictionary() const { - scoped_ptr<DictionaryValue> value(new DictionaryValue()); - - value->SetInteger("id", id); - value->SetString("type", std::string(GetTouchEventLabel(type))); - value->SetString("location", location.ToString()); - value->SetDouble("timestamp", timestamp); - value->SetDouble("radius_x", radius_x); - value->SetDouble("radius_y", radius_y); - value->SetDouble("pressure", pressure); - value->SetInteger("tracking_id", tracking_id); - value->SetInteger("source_device", source_device); - - return value.Pass(); - } - - int id; - ui::EventType type; - gfx::Point location; - double timestamp; - float radius_x; - float radius_y; - float pressure; - int tracking_id; - int source_device; -}; - -// A TouchTrace keeps track of all the touch events of a single touch point -// (starting from a touch-press and ending at touch-release). -class TouchTrace { - public: - typedef std::vector<TouchPointLog>::iterator iterator; - typedef std::vector<TouchPointLog>::const_iterator const_iterator; - typedef std::vector<TouchPointLog>::reverse_iterator reverse_iterator; - typedef std::vector<TouchPointLog>::const_reverse_iterator - const_reverse_iterator; - - TouchTrace() { - } - - void AddTouchPoint(const ui::TouchEvent& touch) { - log_.push_back(TouchPointLog(touch)); - } - - const std::vector<TouchPointLog>& log() const { return log_; } - - bool active() const { - return !log_.empty() && log_.back().type != ui::ET_TOUCH_RELEASED && - log_.back().type != ui::ET_TOUCH_CANCELLED; - } - - // Returns a list containing data from all events for the touch point. - scoped_ptr<ListValue> GetAsList() const { - scoped_ptr<ListValue> list(new ListValue()); - for (const_iterator i = log_.begin(); i != log_.end(); ++i) - list->Append((*i).GetAsDictionary().release()); - return list.Pass(); - } - - void Reset() { - log_.clear(); - } - - private: - std::vector<TouchPointLog> log_; - - DISALLOW_COPY_AND_ASSIGN(TouchTrace); -}; - -// A TouchLog keeps track of all touch events of all touch points. -class TouchLog { - public: - TouchLog() : next_trace_index_(0) { - } - - void AddTouchPoint(const ui::TouchEvent& touch) { - if (touch.type() == ui::ET_TOUCH_PRESSED) - StartTrace(touch); - AddToTrace(touch); - } - - void Reset() { - next_trace_index_ = 0; - for (int i = 0; i < kMaxPaths; ++i) - traces_[i].Reset(); - } - - scoped_ptr<ListValue> GetAsList() const { - scoped_ptr<ListValue> list(new ListValue()); - for (int i = 0; i < kMaxPaths; ++i) { - if (!traces_[i].log().empty()) - list->Append(traces_[i].GetAsList().release()); - } - return list.Pass(); - } - - int GetTraceIndex(int touch_id) const { - return touch_id_to_trace_index_.at(touch_id); - } - - const TouchTrace* traces() const { - return traces_; - } - - private: - void StartTrace(const ui::TouchEvent& touch) { - // Find the first inactive spot; otherwise, overwrite the one - // |next_trace_index_| is pointing to. - int old_trace_index = next_trace_index_; - do { - if (!traces_[next_trace_index_].active()) - break; - next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; - } while (next_trace_index_ != old_trace_index); - int touch_id = touch.touch_id(); - traces_[next_trace_index_].Reset(); - touch_id_to_trace_index_[touch_id] = next_trace_index_; - next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; - } - - void AddToTrace(const ui::TouchEvent& touch) { - int touch_id = touch.touch_id(); - int trace_index = touch_id_to_trace_index_[touch_id]; - traces_[trace_index].AddTouchPoint(touch); - } - - TouchTrace traces_[kMaxPaths]; - int next_trace_index_; - - std::map<int, int> touch_id_to_trace_index_; - - DISALLOW_COPY_AND_ASSIGN(TouchLog); -}; - -// TouchHudCanvas draws touch traces in |FULLSCREEN| and |REDUCED_SCALE| modes. -class TouchHudCanvas : public views::View { - public: - explicit TouchHudCanvas(const TouchLog& touch_log) - : touch_log_(touch_log), - scale_(1) { - SetPaintToLayer(true); - SetFillsBoundsOpaquely(false); - - paint_.setStyle(SkPaint::kFill_Style); - } - - virtual ~TouchHudCanvas() {} - - void SetScale(int scale) { - if (scale_ == scale) - return; - scale_ = scale; - gfx::Transform transform; - transform.Scale(1. / scale_, 1. / scale_); - layer()->SetTransform(transform); - } - - int scale() const { return scale_; } - - void TouchPointAdded(int touch_id) { - int trace_index = touch_log_.GetTraceIndex(touch_id); - const TouchTrace& trace = touch_log_.traces()[trace_index]; - const TouchPointLog& point = trace.log().back(); - if (point.type == ui::ET_TOUCH_PRESSED) - StartedTrace(trace_index); - if (point.type != ui::ET_TOUCH_CANCELLED) - AddedPointToTrace(trace_index); - } - - void Clear() { - for (int i = 0; i < kMaxPaths; ++i) - paths_[i].reset(); - - SchedulePaint(); - } - - private: - void StartedTrace(int trace_index) { - paths_[trace_index].reset(); - colors_[trace_index] = SkColorSetA(kColors[trace_index], kAlpha); - } - - void AddedPointToTrace(int trace_index) { - const TouchTrace& trace = touch_log_.traces()[trace_index]; - const TouchPointLog& point = trace.log().back(); - const gfx::Point& location = point.location; - SkScalar x = SkIntToScalar(location.x()); - SkScalar y = SkIntToScalar(location.y()); - SkPoint last; - if (!paths_[trace_index].getLastPt(&last) || x != last.x() || - y != last.y()) { - paths_[trace_index].addCircle(x, y, SkIntToScalar(kPointRadius)); - SchedulePaint(); - } - } - - // Overridden from views::View. - virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { - for (int i = 0; i < kMaxPaths; ++i) { - if (paths_[i].countPoints() == 0) - continue; - paint_.setColor(colors_[i]); - canvas->DrawPath(paths_[i], paint_); - } - } - - SkPaint paint_; - - const TouchLog& touch_log_; - SkPath paths_[kMaxPaths]; - SkColor colors_[kMaxPaths]; - - int scale_; - - DISALLOW_COPY_AND_ASSIGN(TouchHudCanvas); -}; - -// TouchPointView draws a single touch point in |PROJECTION| mode. This object -// manages its own lifetime and deletes itself upon fade-out completion or -// whenever |Remove()| is explicitly called. -class TouchPointView : public views::View, - public ui::AnimationDelegate, - public views::WidgetObserver { - public: - explicit TouchPointView(views::Widget* parent_widget) - : circle_center_(kPointRadius + 1, kPointRadius + 1), - gradient_center_(SkPoint::Make(kPointRadius + 1, - kPointRadius + 1)) { - SetPaintToLayer(true); - SetFillsBoundsOpaquely(false); - - SetSize(gfx::Size(2 * kPointRadius + 2, 2 * kPointRadius + 2)); - - stroke_paint_.setStyle(SkPaint::kStroke_Style); - stroke_paint_.setColor(kProjectionStrokeColor); - - gradient_colors_[0] = kProjectionFillColor; - gradient_colors_[1] = kProjectionStrokeColor; - - gradient_pos_[0] = SkFloatToScalar(0.9f); - gradient_pos_[1] = SkFloatToScalar(1.0f); - - parent_widget->GetContentsView()->AddChildView(this); - - parent_widget->AddObserver(this); - } - - void UpdateTouch(const ui::TouchEvent& touch) { - if (touch.type() == ui::ET_TOUCH_RELEASED || - touch.type() == ui::ET_TOUCH_CANCELLED) { - fadeout_.reset(new ui::LinearAnimation(kFadeoutDurationInMs, - kFadeoutFrameRate, - this)); - fadeout_->Start(); - } else { - SetX(touch.root_location().x() - kPointRadius - 1); - SetY(touch.root_location().y() - kPointRadius - 1); - } - } - - void Remove() { - delete this; - } - - private: - virtual ~TouchPointView() { - GetWidget()->RemoveObserver(this); - parent()->RemoveChildView(this); - } - - // Overridden from views::View. - virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { - int alpha = kProjectionAlpha; - if (fadeout_) - alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0)); - fill_paint_.setAlpha(alpha); - stroke_paint_.setAlpha(alpha); - SkShader* shader = SkGradientShader::CreateRadial( - gradient_center_, - SkIntToScalar(kPointRadius), - gradient_colors_, - gradient_pos_, - arraysize(gradient_colors_), - SkShader::kMirror_TileMode, - NULL); - fill_paint_.setShader(shader); - shader->unref(); - canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), - fill_paint_); - canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), - stroke_paint_); - } - - // Overridden from ui::AnimationDelegate. - virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE { - DCHECK_EQ(fadeout_.get(), animation); - delete this; - } - - virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { - DCHECK_EQ(fadeout_.get(), animation); - SchedulePaint(); - } - - virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE { - AnimationEnded(animation); - } - - // Overridden from views::WidgetObserver. - virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE { - fadeout_->Stop(); - } - - const gfx::Point circle_center_; - const SkPoint gradient_center_; - - SkPaint fill_paint_; - SkPaint stroke_paint_; - SkColor gradient_colors_[2]; - SkScalar gradient_pos_[2]; - - scoped_ptr<ui::Animation> fadeout_; - - DISALLOW_COPY_AND_ASSIGN(TouchPointView); -}; - TouchObserverHUD::TouchObserverHUD(aura::RootWindow* initial_root) : display_id_(initial_root->GetProperty(kDisplayIdKey)), root_window_(initial_root), - mode_(FULLSCREEN), - touch_log_(new TouchLog()) { + widget_(NULL) { const gfx::Display& display = Shell::GetInstance()->display_manager()->GetDisplayForId(display_id_); views::View* content = new views::View; - canvas_ = new TouchHudCanvas(*touch_log_); - content->AddChildView(canvas_); - const gfx::Size& display_size = display.size(); - canvas_->SetSize(display_size); content->SetSize(display_size); - label_container_ = new views::View; - label_container_->SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kVertical, 0, 0, 0)); - - for (int i = 0; i < kMaxTouchPoints; ++i) { - touch_labels_[i] = new views::Label; - touch_labels_[i]->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255)); - touch_labels_[i]->SetShadowColors(SK_ColorWHITE, - SK_ColorWHITE); - touch_labels_[i]->SetShadowOffset(1, 1); - label_container_->AddChildView(touch_labels_[i]); - } - label_container_->SetX(0); - label_container_->SetY(display_size.height() / kReducedScale); - label_container_->SetSize(label_container_->GetPreferredSize()); - label_container_->SetVisible(false); - content->AddChildView(label_container_); - widget_ = new views::Widget(); views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; params.can_activate = false; params.accept_events = false; - params.bounds = gfx::Rect(display_size); + params.bounds = display.bounds(); params.parent = Shell::GetContainer( root_window_, internal::kShellWindowId_OverlayContainer); @@ -525,142 +69,19 @@ TouchObserverHUD::~TouchObserverHUD() { widget_->RemoveObserver(this); } -// static -scoped_ptr<DictionaryValue> TouchObserverHUD::GetAllAsDictionary() { - scoped_ptr<DictionaryValue> value(new DictionaryValue()); - Shell::RootWindowList roots = Shell::GetInstance()->GetAllRootWindows(); - for (Shell::RootWindowList::iterator iter = roots.begin(); - iter != roots.end(); ++iter) { - internal::RootWindowController* controller = GetRootWindowController(*iter); - if (controller->touch_observer_hud()) { - int64 display_id = (*iter)->GetProperty(kDisplayIdKey); - scoped_ptr<ListValue> list = - controller->touch_observer_hud()->GetLogAsList(); - if (!list->empty()) - value->Set(base::Int64ToString(display_id), list.release()); - } - } - return value.Pass(); -} - -void TouchObserverHUD::ChangeToNextMode() { - switch (mode_) { - case FULLSCREEN: - SetMode(REDUCED_SCALE); - break; - case REDUCED_SCALE: - SetMode(PROJECTION); - break; - case PROJECTION: - SetMode(INVISIBLE); - break; - case INVISIBLE: - SetMode(FULLSCREEN); - break; - } -} - void TouchObserverHUD::Clear() { - if (widget_->IsVisible()) - canvas_->Clear(); - for (int i = 0; i < kMaxTouchPoints; ++i) - touch_labels_[i]->SetText(string16()); - label_container_->SetSize(label_container_->GetPreferredSize()); } -scoped_ptr<ListValue> TouchObserverHUD::GetLogAsList() const { - return touch_log_->GetAsList(); -} +void TouchObserverHUD::Remove() { + root_window_->RemovePreTargetHandler(this); -void TouchObserverHUD::SetMode(Mode mode) { - if (mode_ == mode) - return; - // When going out of projection mode, hide all active touch points. - if (mode_ == PROJECTION) { - for (std::map<int, TouchPointView*>::iterator iter = points_.begin(); - iter != points_.end(); ++iter) - iter->second->Remove(); - points_.clear(); - } - mode_ = mode; - switch (mode) { - case FULLSCREEN: - label_container_->SetVisible(false); - canvas_->SetVisible(true); - canvas_->SetScale(1); - canvas_->SchedulePaint(); - widget_->Show(); - break; - case REDUCED_SCALE: - label_container_->SetVisible(true); - canvas_->SetVisible(true); - canvas_->SetScale(kReducedScale); - canvas_->SchedulePaint(); - widget_->Show(); - break; - case PROJECTION: - label_container_->SetVisible(false); - canvas_->SetVisible(false); - widget_->Show(); - break; - case INVISIBLE: - widget_->Hide(); - break; - } -} + RootWindowController* controller = GetRootWindowController(root_window_); + UnsetHudForRootWindowController(controller); -void TouchObserverHUD::UpdateTouchPointLabel(int index) { - int trace_index = touch_log_->GetTraceIndex(index); - const TouchTrace& trace = touch_log_->traces()[trace_index]; - TouchTrace::const_reverse_iterator point = trace.log().rbegin(); - ui::EventType touch_status = point->type; - float touch_radius = std::max(point->radius_x, point->radius_y); - while (point != trace.log().rend() && point->type == ui::ET_TOUCH_CANCELLED) - point++; - DCHECK(point != trace.log().rend()); - gfx::Point touch_position = point->location; - - std::string string = base::StringPrintf("%2d: %s %s (%.4f)", - index, - GetTouchEventLabel(touch_status), - touch_position.ToString().c_str(), - touch_radius); - touch_labels_[index]->SetText(UTF8ToUTF16(string)); + widget_->CloseNow(); } -void TouchObserverHUD::OnTouchEvent(ui::TouchEvent* event) { - if (event->touch_id() >= kMaxTouchPoints) - return; - - touch_log_->AddTouchPoint(*event); - canvas_->TouchPointAdded(event->touch_id()); - - if (mode_ == PROJECTION) { - if (event->type() == ui::ET_TOUCH_PRESSED) { - TouchPointView* point = new TouchPointView(widget_); - point->UpdateTouch(*event); - std::pair<std::map<int, TouchPointView*>::iterator, bool> result = - points_.insert(std::make_pair(event->touch_id(), point)); - // If a |TouchPointView| is already mapped to the touch id, remove it and - // replace it with the new one. - if (!result.second) { - result.first->second->Remove(); - result.first->second = point; - } - } else { - std::map<int, TouchPointView*>::iterator iter = - points_.find(event->touch_id()); - if (iter != points_.end()) { - iter->second->UpdateTouch(*event); - if (event->type() == ui::ET_TOUCH_RELEASED || - event->type() == ui::ET_TOUCH_CANCELLED) - points_.erase(iter); - } - } - } - - UpdateTouchPointLabel(event->touch_id()); - label_container_->SetSize(label_container_->GetPreferredSize()); +void TouchObserverHUD::OnTouchEvent(ui::TouchEvent* /*event*/) { } void TouchObserverHUD::OnWidgetDestroying(views::Widget* widget) { @@ -671,10 +92,7 @@ void TouchObserverHUD::OnWidgetDestroying(views::Widget* widget) { void TouchObserverHUD::OnDisplayBoundsChanged(const gfx::Display& display) { if (display.id() != display_id_) return; - const gfx::Size& size = display.size(); - widget_->SetSize(size); - canvas_->SetSize(size); - label_container_->SetY(size.height() / kReducedScale); + widget_->SetSize(display.size()); } void TouchObserverHUD::OnDisplayAdded(const gfx::Display& new_display) {} @@ -700,7 +118,7 @@ void TouchObserverHUD::OnDisplayConfigurationChanging() { root_window_->RemovePreTargetHandler(this); RootWindowController* controller = GetRootWindowController(root_window_); - controller->set_touch_observer_hud(NULL); + UnsetHudForRootWindowController(controller); views::Widget::ReparentNativeView( widget_->GetNativeView(), @@ -723,7 +141,7 @@ void TouchObserverHUD::OnDisplayConfigurationChanged() { internal::kShellWindowId_OverlayContainer)); RootWindowController* controller = GetRootWindowController(root_window_); - controller->set_touch_observer_hud(this); + SetHudForRootWindowController(controller); root_window_->AddPreTargetHandler(this); } diff --git a/ash/touch/touch_observer_hud.h b/ash/touch/touch_observer_hud.h index d1c65eba..850bc5e 100644 --- a/ash/touch/touch_observer_hud.h +++ b/ash/touch/touch_observer_hud.h @@ -5,43 +5,23 @@ #ifndef ASH_TOUCH_TOUCH_OBSERVER_HUD_H_ #define ASH_TOUCH_TOUCH_OBSERVER_HUD_H_ -#include <map> - #include "ash/ash_export.h" #include "ash/display/display_controller.h" -#include "ash/shell.h" -#include "base/memory/scoped_ptr.h" -#include "base/values.h" #include "ui/base/events/event_handler.h" #include "ui/gfx/display_observer.h" -#include "ui/gfx/point.h" #include "ui/views/widget/widget_observer.h" #if defined(OS_CHROMEOS) #include "chromeos/display/output_configurator.h" #endif // defined(OS_CHROMEOS) -namespace aura { -class Window; -} - -namespace gfx { -class Display; -} - namespace views { -class Label; -class View; class Widget; } namespace ash { namespace internal { -class TouchHudCanvas; -class TouchLog; -class TouchPointView; - // An event filter which handles system level gesture events. Objects of this // class manage their own lifetime. class ASH_EXPORT TouchObserverHUD @@ -53,76 +33,54 @@ class ASH_EXPORT TouchObserverHUD #endif // defined(OS_CHROMEOS) public DisplayController::Observer { public: - enum Mode { - FULLSCREEN, - REDUCED_SCALE, - PROJECTION, - INVISIBLE, - }; - - explicit TouchObserverHUD(aura::RootWindow* initial_root); - - // Returns the log of touch events as a dictionary mapping id of each display - // to its touch log. - static scoped_ptr<DictionaryValue> GetAllAsDictionary(); + // Called to clear touch points and traces from the screen. Default + // implementation does nothing. Sub-classes should implement appropriately. + virtual void Clear(); - // Changes the display mode (e.g. scale, visibility). Calling this repeatedly - // cycles between a fixed number of display modes. - void ChangeToNextMode(); + // Removes the HUD from the screen. + void Remove(); - // Removes all existing touch points from the screen (only if the HUD is - // visible). - void Clear(); + int64 display_id() const { return display_id_; } - // Returns log of touch events as a list value. Each item in the list is a - // trace of one touch point. - scoped_ptr<ListValue> GetLogAsList() const; - - Mode mode() const { return mode_; } - - private: - friend class TouchHudTest; + protected: + explicit TouchObserverHUD(aura::RootWindow* initial_root); virtual ~TouchObserverHUD(); - void SetMode(Mode mode); + virtual void SetHudForRootWindowController( + RootWindowController* controller) = 0; + virtual void UnsetHudForRootWindowController( + RootWindowController* controller) = 0; - void UpdateTouchPointLabel(int index); + views::Widget* widget() { return widget_; } - // Overriden from ui::EventHandler: + // Overriden from ui::EventHandler. virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE; - // Overridden from views::WidgetObserver: + // Overridden from views::WidgetObserver. virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE; - // Overridden from gfx::DisplayObserver: + // Overridden from gfx::DisplayObserver. virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE; virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE; virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE; #if defined(OS_CHROMEOS) - // Overriden from chromeos::OutputConfigurator::Observer: + // Overriden from chromeos::OutputConfigurator::Observer. virtual void OnDisplayModeChanged() OVERRIDE; #endif // defined(OS_CHROMEOS) - // Overriden form DisplayController::Observer: + // Overriden form DisplayController::Observer. virtual void OnDisplayConfigurationChanging() OVERRIDE; virtual void OnDisplayConfigurationChanged() OVERRIDE; - static const int kMaxTouchPoints = 32; + private: + friend class TouchHudTest; const int64 display_id_; aura::RootWindow* root_window_; - Mode mode_; - - scoped_ptr<TouchLog> touch_log_; - views::Widget* widget_; - TouchHudCanvas* canvas_; - std::map<int, TouchPointView*> points_; - views::View* label_container_; - views::Label* touch_labels_[kMaxTouchPoints]; DISALLOW_COPY_AND_ASSIGN(TouchObserverHUD); }; diff --git a/ash/touch/touch_observer_hud_unittest.cc b/ash/touch/touch_observer_hud_unittest.cc index 7e8b91b..0399407 100644 --- a/ash/touch/touch_observer_hud_unittest.cc +++ b/ash/touch/touch_observer_hud_unittest.cc @@ -7,8 +7,10 @@ #include "ash/ash_switches.h" #include "ash/display/display_manager.h" #include "ash/root_window_controller.h" +#include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/display_manager_test_api.h" +#include "ash/touch/touch_hud_debug.h" #include "ash/wm/property_util.h" #include "base/command_line.h" #include "base/format_macros.h" @@ -208,19 +210,19 @@ class TouchHudTest : public test::AshTestBase { } internal::TouchObserverHUD* GetInternalTouchHud() { - return GetInternalRootController()->touch_observer_hud(); + return GetInternalRootController()->touch_hud_debug(); } internal::TouchObserverHUD* GetExternalTouchHud() { - return GetExternalRootController()->touch_observer_hud(); + return GetExternalRootController()->touch_hud_debug(); } internal::TouchObserverHUD* GetPrimaryTouchHud() { - return GetPrimaryRootController()->touch_observer_hud(); + return GetPrimaryRootController()->touch_hud_debug(); } internal::TouchObserverHUD* GetSecondaryTouchHud() { - return GetSecondaryRootController()->touch_observer_hud(); + return GetSecondaryRootController()->touch_hud_debug(); } DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) { |