| // Copyright 2018 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/assistant/ui/main_stage/assistant_card_element_view.h" |
| |
| #include <memory> |
| |
| #include "ash/assistant/model/assistant_ui_element.h" |
| #include "ash/assistant/ui/assistant_container_view.h" |
| #include "ash/assistant/ui/assistant_ui_constants.h" |
| #include "ash/assistant/ui/assistant_view_delegate.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/events/event.h" |
| #include "ui/events/event_sink.h" |
| #include "ui/events/event_utils.h" |
| #include "ui/views/accessibility/view_accessibility.h" |
| #include "ui/views/layout/fill_layout.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Helpers --------------------------------------------------------------------- |
| |
| void CreateAndSendMouseClick(aura::WindowTreeHost* host, |
| const gfx::Point& location_in_pixels) { |
| ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, location_in_pixels, |
| location_in_pixels, ui::EventTimeForNow(), |
| ui::EF_LEFT_MOUSE_BUTTON, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| |
| // Send an ET_MOUSE_PRESSED event. |
| ui::EventDispatchDetails details = |
| host->event_sink()->OnEventFromSource(&press_event); |
| |
| if (details.dispatcher_destroyed) |
| return; |
| |
| ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, location_in_pixels, |
| location_in_pixels, ui::EventTimeForNow(), |
| ui::EF_LEFT_MOUSE_BUTTON, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| |
| // Send an ET_MOUSE_RELEASED event. |
| ignore_result(host->event_sink()->OnEventFromSource(&release_event)); |
| } |
| |
| } // namespace |
| |
| AssistantCardElementView::AssistantCardElementView( |
| AssistantViewDelegate* delegate, |
| const AssistantCardElement* card_element) |
| : delegate_(delegate), |
| contents_(const_cast<AssistantCardElement*>(card_element)->contents()) { |
| InitLayout(card_element); |
| |
| // We observe |contents_| to receive events pertaining to the underlying web |
| // contents including auto-resize and suppressed navigation events. |
| contents_->AddObserver(this); |
| } |
| |
| AssistantCardElementView::~AssistantCardElementView() { |
| contents_->RemoveObserver(this); |
| } |
| |
| const char* AssistantCardElementView::GetClassName() const { |
| return "AssistantCardElementView"; |
| } |
| |
| void AssistantCardElementView::AddedToWidget() { |
| aura::Window* const top_level_window = native_view()->GetToplevelWindow(); |
| |
| // Find the window for the Assistant card. |
| aura::Window* window = native_view(); |
| while (window->parent() != top_level_window) |
| window = window->parent(); |
| |
| // The Assistant card window will consume all events that enter it. This |
| // prevents us from being able to scroll the native view hierarchy |
| // vertically. As such, we need to prevent the Assistant card window from |
| // receiving events it doesn't need. It needs mouse click events for |
| // handling links. |
| window->SetProperty(ash::assistant::ui::kOnlyAllowMouseClickEvents, true); |
| } |
| |
| void AssistantCardElementView::ChildPreferredSizeChanged(views::View* child) { |
| PreferredSizeChanged(); |
| } |
| |
| void AssistantCardElementView::AboutToRequestFocusFromTabTraversal( |
| bool reverse) { |
| contents_->FocusThroughTabTraversal(reverse); |
| } |
| |
| void AssistantCardElementView::OnFocus() { |
| contents_->Focus(); |
| } |
| |
| void AssistantCardElementView::OnGestureEvent(ui::GestureEvent* event) { |
| // We need to route GESTURE_TAP events to our Assistant card because links |
| // should be tappable. The Assistant card window will not receive gesture |
| // events so we convert the gesture into analogous mouse events. |
| if (event->type() != ui::ET_GESTURE_TAP) { |
| views::View::OnGestureEvent(event); |
| return; |
| } |
| |
| // Consume the original event. |
| event->StopPropagation(); |
| event->SetHandled(); |
| |
| aura::Window* root_window = GetWidget()->GetNativeWindow()->GetRootWindow(); |
| |
| // Get the appropriate event location in pixels. |
| gfx::Point location_in_pixels = event->location(); |
| ConvertPointToScreen(this, &location_in_pixels); |
| aura::WindowTreeHost* host = root_window->GetHost(); |
| host->ConvertDIPToPixels(&location_in_pixels); |
| |
| wm::CursorManager* cursor_manager = delegate_->GetCursorManager(); |
| |
| // We want to prevent the cursor from changing its visibility during our |
| // mouse events because we are actually handling a gesture. To accomplish |
| // this, we cache the cursor's visibility and lock it in its current state. |
| const bool visible = cursor_manager->IsCursorVisible(); |
| cursor_manager->LockCursor(); |
| |
| CreateAndSendMouseClick(host, location_in_pixels); |
| |
| // Restore the original cursor visibility that may have changed during our |
| // sequence of mouse events. This change would not have been perceivable to |
| // the user since it occurred within our lock. |
| if (visible) |
| cursor_manager->ShowCursor(); |
| else |
| cursor_manager->HideCursor(); |
| |
| // Release our cursor lock. |
| cursor_manager->UnlockCursor(); |
| } |
| |
| void AssistantCardElementView::DidAutoResizeView(const gfx::Size& new_size) { |
| contents_->GetView()->view()->SetPreferredSize(new_size); |
| } |
| |
| void AssistantCardElementView::DidSuppressNavigation( |
| const GURL& url, |
| WindowOpenDisposition disposition, |
| bool from_user_gesture) { |
| // We delegate navigation to the AssistantController so that it can apply |
| // special handling to deep links. |
| if (from_user_gesture) |
| delegate_->OpenUrlFromView(url); |
| } |
| |
| void AssistantCardElementView::InitLayout( |
| const AssistantCardElement* card_element) { |
| SetFocusBehavior(FocusBehavior::ALWAYS); |
| SetLayoutManager(std::make_unique<views::FillLayout>()); |
| |
| // Contents view. |
| AddChildView(contents_->GetView()->view()); |
| |
| // OverrideDescription() doesn't work. Only names are read automatically. |
| GetViewAccessibility().OverrideName(card_element->fallback()); |
| } |
| |
| } // namespace ash |