1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ash/assistant/ui/dialog_plate/mic_view.h" 6 7 #include <memory> 8 9 #include "ash/assistant/model/assistant_interaction_model.h" 10 #include "ash/assistant/model/assistant_ui_model.h" 11 #include "ash/assistant/ui/logo_view/logo_view.h" 12 #include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h" 13 #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h" 14 #include "ui/views/layout/box_layout.h" 15 #include "ui/views/layout/fill_layout.h" 16 17 namespace ash { 18 19 namespace { 20 21 // Appearance. 22 // The desired height for the LogoView icon is 24dip in mic state to match the 23 // static mic button in DialogPlate. The |kMicIcon| resource used for the static 24 // button has different internal padding than does that of the icon drawn by 25 // LogoView, so we add 2dip for visual consistency. 26 constexpr int kIconSizeDip = 26; 27 constexpr int kPreferredSizeDip = 32; 28 29 } // namespace 30 MicView(AssistantButtonListener * listener,AssistantButtonId button_id)31MicView::MicView(AssistantButtonListener* listener, AssistantButtonId button_id) 32 : AssistantButton(listener, button_id) { 33 InitLayout(); 34 35 assistant_controller_observer_.Add(AssistantController::Get()); 36 AssistantInteractionController::Get()->GetModel()->AddObserver(this); 37 } 38 ~MicView()39MicView::~MicView() { 40 if (AssistantInteractionController::Get()) 41 AssistantInteractionController::Get()->GetModel()->RemoveObserver(this); 42 } 43 GetClassName() const44const char* MicView::GetClassName() const { 45 return "MicView"; 46 } 47 CalculatePreferredSize() const48gfx::Size MicView::CalculatePreferredSize() const { 49 return gfx::Size(kPreferredSizeDip, GetHeightForWidth(kPreferredSizeDip)); 50 } 51 GetHeightForWidth(int width) const52int MicView::GetHeightForWidth(int width) const { 53 return kPreferredSizeDip; 54 } 55 OnAssistantControllerDestroying()56void MicView::OnAssistantControllerDestroying() { 57 AssistantInteractionController::Get()->GetModel()->RemoveObserver(this); 58 assistant_controller_observer_.Remove(AssistantController::Get()); 59 } 60 OnMicStateChanged(MicState mic_state)61void MicView::OnMicStateChanged(MicState mic_state) { 62 is_user_speaking_ = false; 63 UpdateState(/*animate=*/true); 64 } 65 OnSpeechLevelChanged(float speech_level_db)66void MicView::OnSpeechLevelChanged(float speech_level_db) { 67 // TODO: Work with UX to determine the threshold. 68 constexpr float kSpeechLevelThreshold = -60.0f; 69 if (speech_level_db < kSpeechLevelThreshold) 70 return; 71 72 logo_view_->SetSpeechLevel(speech_level_db); 73 if (!is_user_speaking_) { 74 is_user_speaking_ = true; 75 UpdateState(/*animate=*/true); 76 } 77 } 78 InitLayout()79void MicView::InitLayout() { 80 SetLayoutManager(std::make_unique<views::FillLayout>()); 81 82 // Logo view container. 83 auto logo_view_container = std::make_unique<views::View>(); 84 logo_view_container->SetCanProcessEventsWithinSubtree(false); 85 86 views::BoxLayout* layout_manager = 87 logo_view_container->SetLayoutManager(std::make_unique<views::BoxLayout>( 88 views::BoxLayout::Orientation::kVertical)); 89 90 layout_manager->set_cross_axis_alignment( 91 views::BoxLayout::CrossAxisAlignment::kCenter); 92 93 layout_manager->set_main_axis_alignment( 94 views::BoxLayout::MainAxisAlignment::kCenter); 95 96 // Logo view. 97 logo_view_ = logo_view_container->AddChildView(LogoView::Create()); 98 logo_view_->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip)); 99 100 AddChildView(std::move(logo_view_container)); 101 102 // Initialize state. 103 UpdateState(/*animate=*/false); 104 } 105 UpdateState(bool animate)106void MicView::UpdateState(bool animate) { 107 const AssistantInteractionModel* interaction_model = 108 AssistantInteractionController::Get()->GetModel(); 109 110 if (animate) { 111 // If Assistant UI is not visible, we shouldn't attempt to animate state 112 // changes. We should instead advance immediately to the next state. 113 animate = AssistantUiController::Get()->GetModel()->visibility() == 114 AssistantVisibility::kVisible; 115 } 116 117 LogoView::State mic_state; 118 switch (interaction_model->mic_state()) { 119 case MicState::kClosed: 120 mic_state = LogoView::State::kMic; 121 break; 122 case MicState::kOpen: 123 mic_state = is_user_speaking_ ? LogoView::State::kUserSpeaks 124 : LogoView::State::kListening; 125 break; 126 } 127 logo_view_->SetState(mic_state, animate); 128 } 129 130 } // namespace ash 131