blob: 0617981e279ebb8093a6d3d523cdf36b1ec9ffdb [file] [log] [blame]
// Copyright (c) 2012 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/system/status_area_widget.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/config.h"
#include "ash/session/session_controller.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/system/accessibility/dictation_button_tray.h"
#include "ash/system/accessibility/select_to_speak_tray.h"
#include "ash/system/flag_warning/flag_warning_tray.h"
#include "ash/system/ime_menu/ime_menu_tray.h"
#include "ash/system/message_center/notification_tray.h"
#include "ash/system/overview/overview_button_tray.h"
#include "ash/system/palette/palette_tray.h"
#include "ash/system/session/logout_button_tray.h"
#include "ash/system/status_area_widget_delegate.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ash/system/virtual_keyboard/virtual_keyboard_tray.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/command_line.h"
#include "base/i18n/time_formatting.h"
#include "ui/base/ui_base_features.h"
#include "ui/display/display.h"
#include "ui/native_theme/native_theme_dark_aura.h"
namespace ash {
StatusAreaWidget::StatusAreaWidget(aura::Window* status_container, Shelf* shelf)
: status_area_widget_delegate_(new StatusAreaWidgetDelegate(shelf)),
shelf_(shelf) {
DCHECK(status_container);
DCHECK(shelf);
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.delegate = status_area_widget_delegate_;
params.name = "StatusAreaWidget";
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.parent = status_container;
Init(params);
set_focus_on_creation(false);
SetContentsView(status_area_widget_delegate_);
}
void StatusAreaWidget::Initialize() {
// Create the child views, right to left.
overview_button_tray_ = std::make_unique<OverviewButtonTray>(shelf_);
status_area_widget_delegate_->AddChildView(overview_button_tray_.get());
if (features::IsSystemTrayUnifiedEnabled()) {
unified_system_tray_ = std::make_unique<UnifiedSystemTray>(shelf_);
status_area_widget_delegate_->AddChildView(unified_system_tray_.get());
} else {
system_tray_ = std::make_unique<SystemTray>(shelf_);
status_area_widget_delegate_->AddChildView(system_tray_.get());
}
// Must happen after the widget is initialized so the native window exists.
if (!features::IsSystemTrayUnifiedEnabled()) {
notification_tray_ =
std::make_unique<NotificationTray>(shelf_, GetNativeWindow());
status_area_widget_delegate_->AddChildView(notification_tray_.get());
}
palette_tray_ = std::make_unique<PaletteTray>(shelf_);
status_area_widget_delegate_->AddChildView(palette_tray_.get());
virtual_keyboard_tray_ = std::make_unique<VirtualKeyboardTray>(shelf_);
status_area_widget_delegate_->AddChildView(virtual_keyboard_tray_.get());
ime_menu_tray_ = std::make_unique<ImeMenuTray>(shelf_);
status_area_widget_delegate_->AddChildView(ime_menu_tray_.get());
select_to_speak_tray_ = std::make_unique<SelectToSpeakTray>(shelf_);
status_area_widget_delegate_->AddChildView(select_to_speak_tray_.get());
dictation_button_tray_ = std::make_unique<DictationButtonTray>(shelf_);
status_area_widget_delegate_->AddChildView(dictation_button_tray_.get());
logout_button_tray_ = std::make_unique<LogoutButtonTray>(shelf_);
status_area_widget_delegate_->AddChildView(logout_button_tray_.get());
if (!::features::IsAshInBrowserProcess()) {
// Flag warning tray is not currently used in non-MASH environments, because
// mus will roll out via experiment/Finch trial and showing the tray would
// reveal the experiment state to users.
flag_warning_tray_ = std::make_unique<FlagWarningTray>(shelf_);
status_area_widget_delegate_->AddChildView(flag_warning_tray_.get());
}
// The layout depends on the number of children, so build it once after
// adding all of them.
status_area_widget_delegate_->UpdateLayout();
// Initialize after all trays have been created.
if (notification_tray_) {
system_tray_->InitializeTrayItems(notification_tray_.get());
notification_tray_->Initialize();
}
palette_tray_->Initialize();
virtual_keyboard_tray_->Initialize();
ime_menu_tray_->Initialize();
select_to_speak_tray_->Initialize();
if (dictation_button_tray_)
dictation_button_tray_->Initialize();
overview_button_tray_->Initialize();
UpdateAfterShelfAlignmentChange();
UpdateAfterLoginStatusChange(
Shell::Get()->session_controller()->login_status());
// NOTE: Container may be hidden depending on login/display state.
Show();
}
StatusAreaWidget::~StatusAreaWidget() {
if (system_tray_)
system_tray_->Shutdown();
notification_tray_.reset();
// Must be destroyed after |notification_tray_|.
system_tray_.reset();
unified_system_tray_.reset();
ime_menu_tray_.reset();
select_to_speak_tray_.reset();
dictation_button_tray_.reset();
virtual_keyboard_tray_.reset();
palette_tray_.reset();
logout_button_tray_.reset();
overview_button_tray_.reset();
flag_warning_tray_.reset();
// All child tray views have been removed.
DCHECK_EQ(0, GetContentsView()->child_count());
}
void StatusAreaWidget::UpdateAfterShelfAlignmentChange() {
if (system_tray_)
system_tray_->UpdateAfterShelfAlignmentChange();
if (unified_system_tray_)
unified_system_tray_->UpdateAfterShelfAlignmentChange();
if (notification_tray_)
notification_tray_->UpdateAfterShelfAlignmentChange();
logout_button_tray_->UpdateAfterShelfAlignmentChange();
virtual_keyboard_tray_->UpdateAfterShelfAlignmentChange();
ime_menu_tray_->UpdateAfterShelfAlignmentChange();
select_to_speak_tray_->UpdateAfterShelfAlignmentChange();
if (dictation_button_tray_)
dictation_button_tray_->UpdateAfterShelfAlignmentChange();
palette_tray_->UpdateAfterShelfAlignmentChange();
overview_button_tray_->UpdateAfterShelfAlignmentChange();
if (flag_warning_tray_)
flag_warning_tray_->UpdateAfterShelfAlignmentChange();
status_area_widget_delegate_->UpdateLayout();
}
void StatusAreaWidget::UpdateAfterLoginStatusChange(LoginStatus login_status) {
if (login_status_ == login_status)
return;
login_status_ = login_status;
if (system_tray_)
system_tray_->UpdateAfterLoginStatusChange(login_status);
if (unified_system_tray_)
unified_system_tray_->UpdateAfterLoginStatusChange();
logout_button_tray_->UpdateAfterLoginStatusChange();
overview_button_tray_->UpdateAfterLoginStatusChange(login_status);
}
void StatusAreaWidget::SetSystemTrayVisibility(bool visible) {
TrayBackgroundView* tray =
unified_system_tray_
? static_cast<TrayBackgroundView*>(unified_system_tray_.get())
: static_cast<TrayBackgroundView*>(system_tray_.get());
tray->SetVisible(visible);
// Opacity is set to prevent flakiness in kiosk browser tests. See
// https://crbug.com/624584.
SetOpacity(visible ? 1.f : 0.f);
if (visible) {
Show();
} else {
tray->CloseBubble();
Hide();
}
}
TrayBackgroundView* StatusAreaWidget::GetSystemTrayAnchor() const {
if (Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled()) {
return overview_button_tray_.get();
}
if (unified_system_tray_)
return unified_system_tray_.get();
return system_tray_.get();
}
bool StatusAreaWidget::ShouldShowShelf() const {
// If UnifiedSystemTray is enabled, and it has main bubble, return true.
if (unified_system_tray_ && unified_system_tray_->IsBubbleShown())
return true;
// If UnifiedSystemTray is enabled, and it has a slider bubble, return false.
if (unified_system_tray_ && unified_system_tray_->IsSliderBubbleShown())
return false;
// The system tray bubble may or may not want to force the shelf to be
// visible.
if (system_tray_ && system_tray_->IsSystemBubbleVisible())
return system_tray_->ShouldShowShelf();
// All other tray bubbles will force the shelf to be visible.
return views::TrayBubbleView::IsATrayBubbleOpen();
}
bool StatusAreaWidget::IsMessageBubbleShown() const {
return (unified_system_tray_ && unified_system_tray_->IsBubbleShown()) ||
(!unified_system_tray_ && system_tray_->IsSystemBubbleVisible()) ||
(notification_tray_ && notification_tray_->IsMessageCenterVisible());
}
void StatusAreaWidget::SchedulePaint() {
status_area_widget_delegate_->SchedulePaint();
if (notification_tray_)
notification_tray_->SchedulePaint();
if (system_tray_)
system_tray_->SchedulePaint();
if (unified_system_tray_)
unified_system_tray_->SchedulePaint();
virtual_keyboard_tray_->SchedulePaint();
logout_button_tray_->SchedulePaint();
ime_menu_tray_->SchedulePaint();
select_to_speak_tray_->SchedulePaint();
if (dictation_button_tray_)
dictation_button_tray_->SchedulePaint();
palette_tray_->SchedulePaint();
overview_button_tray_->SchedulePaint();
if (flag_warning_tray_)
flag_warning_tray_->SchedulePaint();
}
const ui::NativeTheme* StatusAreaWidget::GetNativeTheme() const {
return ui::NativeThemeDarkAura::instance();
}
bool StatusAreaWidget::OnNativeWidgetActivationChanged(bool active) {
if (!Widget::OnNativeWidgetActivationChanged(active))
return false;
if (active)
status_area_widget_delegate_->SetPaneFocusAndFocusDefault();
return true;
}
void StatusAreaWidget::UpdateShelfItemBackground(SkColor color) {
if (notification_tray_)
notification_tray_->UpdateShelfItemBackground(color);
if (system_tray_)
system_tray_->UpdateShelfItemBackground(color);
if (unified_system_tray_)
unified_system_tray_->UpdateShelfItemBackground(color);
virtual_keyboard_tray_->UpdateShelfItemBackground(color);
ime_menu_tray_->UpdateShelfItemBackground(color);
select_to_speak_tray_->UpdateShelfItemBackground(color);
if (dictation_button_tray_)
dictation_button_tray_->UpdateShelfItemBackground(color);
palette_tray_->UpdateShelfItemBackground(color);
overview_button_tray_->UpdateShelfItemBackground(color);
}
} // namespace ash