Index: ui/views/bubble/tray_bubble_view.cc |
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc |
index 9f106c168b7633118f05d0baad7fa7948346138d..194c9cd183b99123e4149535969d1412147f6c6a 100644 |
--- a/ui/views/bubble/tray_bubble_view.cc |
+++ b/ui/views/bubble/tray_bubble_view.cc |
@@ -194,7 +194,7 @@ TrayBubbleView::TrayBubbleView(const InitParams& init_params) |
bubble_border_->set_alignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
bubble_border_->set_paint_arrow(BubbleBorder::PAINT_NONE); |
set_parent_window(params_.parent_window); |
- set_can_activate(params_.can_activate); |
+ set_can_activate(false); |
set_notify_enter_exit_on_child(true); |
set_close_on_deactivate(init_params.close_on_deactivate); |
set_margins(gfx::Insets()); |
@@ -209,9 +209,12 @@ TrayBubbleView::TrayBubbleView(const InitParams& init_params) |
TrayBubbleView::~TrayBubbleView() { |
mouse_watcher_.reset(); |
- // Inform host items (models) that their views are being destroyed. |
- if (delegate_) |
+ if (delegate_) { |
+ delegate_->UnregisterAllAccelerators(this); |
+ |
+ // Inform host items (models) that their views are being destroyed. |
delegate_->BubbleViewDestroyed(); |
+ } |
} |
// static |
@@ -228,6 +231,17 @@ void TrayBubbleView::InitializeAndShowBubble() { |
UpdateBubble(); |
++g_current_tray_bubble_showing_count_; |
+ |
+ // If TrayBubbleView cannot be activated, register accelerators to capture key |
+ // events for activating the view or closing it. TrayBubbleView expects that |
+ // those accelerators are registered at the global level. |
+ if (delegate_ && !CanActivate()) { |
+ delegate_->RegisterAccelerators( |
+ {ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE), |
+ ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE), |
+ ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN)}, |
+ this); |
+ } |
} |
void TrayBubbleView::UpdateBubble() { |
@@ -235,6 +249,11 @@ void TrayBubbleView::UpdateBubble() { |
SizeToContents(); |
bubble_content_mask_->layer()->SetBounds(layer()->bounds()); |
GetWidget()->GetRootView()->SchedulePaint(); |
+ |
+ // When extra keyboard accessibility is enabled, focus the default item if |
+ // no item is focused. |
+ if (delegate_ && delegate_->ShouldEnableExtraKeyboardAccessibility()) |
+ FocusDefaultIfNeeded(); |
} |
} |
@@ -261,6 +280,13 @@ gfx::Insets TrayBubbleView::GetBorderInsets() const { |
return bubble_border_->GetInsets(); |
} |
+void TrayBubbleView::ResetDelegate() { |
+ if (delegate_) |
+ delegate_->UnregisterAllAccelerators(this); |
+ |
+ delegate_ = nullptr; |
+} |
+ |
int TrayBubbleView::GetDialogButtons() const { |
return ui::DIALOG_BUTTON_NONE; |
} |
@@ -371,6 +397,26 @@ void TrayBubbleView::MouseMovedOutOfHost() { |
mouse_watcher_->Stop(); |
} |
+bool TrayBubbleView::AcceleratorPressed(const ui::Accelerator& accelerator) { |
+ if (accelerator == ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)) { |
+ CloseBubbleView(); |
+ return true; |
+ } |
+ |
+ if (accelerator == ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE) || |
+ accelerator == ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN)) { |
+ ui::KeyEvent key_event( |
+ accelerator.key_state() == ui::Accelerator::KeyState::PRESSED |
+ ? ui::EventType::ET_KEY_PRESSED |
+ : ui::EventType::ET_KEY_RELEASED, |
+ accelerator.key_code(), accelerator.modifiers()); |
+ ActivateAndStartNavigation(key_event); |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
void TrayBubbleView::ChildPreferredSizeChanged(View* child) { |
SizeToContents(); |
} |
@@ -383,4 +429,42 @@ void TrayBubbleView::ViewHierarchyChanged( |
} |
} |
+void TrayBubbleView::CloseBubbleView() { |
+ if (!delegate_) |
+ return; |
+ |
+ delegate_->UnregisterAllAccelerators(this); |
+ delegate_->HideBubble(this); |
+} |
+ |
+void TrayBubbleView::ActivateAndStartNavigation(const ui::KeyEvent& key_event) { |
+ // No need to explicitly activate the widget. FocusManager will activate it if |
+ // necessary. |
+ set_can_activate(true); |
+ |
+ if (!GetWidget()->GetFocusManager()->OnKeyEvent(key_event) && delegate_) { |
+ // No need to handle accelerators by TrayBubbleView after focus has moved to |
+ // the widget. The focused view will handle focus traversal. |
+ // FocusManager::OnKeyEvent returns false when it consumes a key event. |
+ delegate_->UnregisterAllAccelerators(this); |
+ } |
+} |
+ |
+void TrayBubbleView::FocusDefaultIfNeeded() { |
+ views::FocusManager* manager = GetFocusManager(); |
+ if (!manager || manager->GetFocusedView()) |
+ return; |
+ |
+ views::View* view = |
+ manager->GetNextFocusableView(nullptr, nullptr, false, false); |
+ if (!view) |
+ return; |
+ |
+ // No need to explicitly activate the widget. View::RequestFocus will activate |
+ // it if necessary. |
+ set_can_activate(true); |
+ |
+ view->RequestFocus(); |
+} |
+ |
} // namespace views |