| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/shelf/shelf_focus_cycler.h" |
| |
| #include "ash/focus/focus_cycler.h" |
| #include "ash/shelf/desk_button_widget.h" |
| #include "ash/shelf/login_shelf_view.h" |
| #include "ash/shelf/login_shelf_widget.h" |
| #include "ash/shelf/scrollable_shelf_view.h" |
| #include "ash/shelf/shelf.h" |
| #include "ash/shelf/shelf_navigation_widget.h" |
| #include "ash/shelf/shelf_view.h" |
| #include "ash/shelf/shelf_widget.h" |
| #include "ash/shell.h" |
| #include "ash/system/status_area_widget.h" |
| #include "ash/system/status_area_widget_delegate.h" |
| #include "ash/system/tray/system_tray_notifier.h" |
| #include "ash/wm/desks/desk_button/desk_button_container.h" |
| #include "base/i18n/rtl.h" |
| |
| namespace ash { |
| |
| ShelfFocusCycler::ShelfFocusCycler(Shelf* shelf) : shelf_(shelf) {} |
| |
| void ShelfFocusCycler::FocusOut(bool reverse, SourceView source_view) { |
| // TODO(manucornet): Once the non-views-based shelf is gone, make this a |
| // simple cycling logic instead of a long switch. |
| switch (source_view) { |
| case SourceView::kShelfNavigationView: |
| if (reverse) { |
| FocusStatusArea(reverse); |
| } else { |
| FocusDeskButton(reverse); |
| } |
| break; |
| case SourceView::kDeskButton: |
| if (reverse) { |
| FocusNavigation(reverse); |
| } else { |
| FocusShelf(reverse); |
| } |
| break; |
| case SourceView::kShelfView: |
| if (reverse) |
| FocusDeskButton(reverse); |
| else |
| FocusStatusArea(reverse); |
| break; |
| case SourceView::kStatusAreaView: { |
| // If we are using a views-based shelf: |
| // * If we're in an active session, either focus the navigation widget |
| // (going forward) or the shelf (reverse). |
| // * Otherwise (login/lock screen, OOBE), bring focus to the shelf only |
| // if we're going in reverse; if we're going forward, let the system |
| // tray focus observers focus the lock/login view. |
| if (shelf_->shelf_widget()->GetLoginShelfView()->GetVisible() && |
| (!reverse || |
| (!shelf_->shelf_widget()->GetLoginShelfView()->IsFocusable() && |
| reverse))) { |
| // Login/lock screen or OOBE. |
| Shell::Get()->system_tray_notifier()->NotifyFocusOut(reverse); |
| } else if (reverse) { |
| FocusShelf(reverse); |
| } else { |
| FocusNavigation(reverse); |
| } |
| break; |
| } |
| } |
| } |
| |
| void ShelfFocusCycler::FocusNavigation(bool last_element) { |
| ShelfNavigationWidget* navigation_widget = shelf_->navigation_widget(); |
| if (!navigation_widget->GetHomeButton() && |
| !navigation_widget->GetBackButton()) { |
| FocusOut(last_element, SourceView::kShelfNavigationView); |
| return; |
| } |
| navigation_widget->PrepareForGettingFocus(last_element); |
| Shell::Get()->focus_cycler()->FocusWidget(navigation_widget); |
| } |
| |
| void ShelfFocusCycler::FocusDeskButton(bool last_element) { |
| DeskButtonWidget* desk_button_widget = shelf_->desk_button_widget(); |
| if (desk_button_widget && desk_button_widget->ShouldBeVisible()) { |
| // For LTR layout, last/first element means last/first element in the view |
| // hierarchy; for RTL, last/first element means first/last. |
| views::View* default_child_to_focus = |
| desk_button_widget->GetFocusManager()->GetNextFocusableView( |
| /*starting_view=*/nullptr, /*starting_widget=*/nullptr, |
| /*reverse=*/base::i18n::IsRTL() != last_element, |
| /*dont_loop=*/false); |
| desk_button_widget->SetDefaultChildToFocus(default_child_to_focus); |
| Shell::Get()->focus_cycler()->FocusWidget(desk_button_widget); |
| } else if (last_element) { |
| FocusNavigation(last_element); |
| } else { |
| FocusShelf(last_element); |
| } |
| } |
| |
| void ShelfFocusCycler::FocusShelf(bool last_element) { |
| if (shelf_->shelf_widget()->GetLoginShelfView()->GetVisible()) { |
| LoginShelfWidget* login_shelf_widget = shelf_->login_shelf_widget(); |
| login_shelf_widget->SetDefaultLastFocusableChild(last_element); |
| Shell::Get()->focus_cycler()->FocusWidget(login_shelf_widget); |
| } else { |
| HotseatWidget* hotseat_widget = shelf_->hotseat_widget(); |
| hotseat_widget->scrollable_shelf_view()->set_default_last_focusable_child( |
| last_element); |
| Shell::Get()->focus_cycler()->FocusWidget(hotseat_widget); |
| } |
| } |
| |
| void ShelfFocusCycler::FocusStatusArea(bool last_element) { |
| StatusAreaWidget* status_area_widget = shelf_->GetStatusAreaWidget(); |
| status_area_widget->status_area_widget_delegate() |
| ->set_default_last_focusable_child(last_element); |
| Shell::Get()->focus_cycler()->FocusWidget(status_area_widget); |
| } |
| |
| } // namespace ash |