chromium/ash/system/ime_menu/ime_menu_tray.cc

// Copyright 2016 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/system/ime_menu/ime_menu_tray.h"

#include <memory>

#include "ash/accessibility/a11y_feature_type.h"
#include "ash/accessibility/accessibility_controller.h"
#include "ash/constants/tray_background_view_catalog.h"
#include "ash/ime/ime_controller_impl.h"
#include "ash/keyboard/keyboard_controller_impl.h"
#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "ash/keyboard/virtual_keyboard_controller.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/public/cpp/ash_view_ids.h"
#include "ash/public/cpp/system_tray_client.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_id.h"
#include "ash/style/icon_button.h"
#include "ash/style/rounded_container.h"
#include "ash/style/typography.h"
#include "ash/system/ime_menu/ime_list_view.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/tray/detailed_view_delegate.h"
#include "ash/system/tray/system_menu_button.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/tray/tray_background_view.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_container.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "ash/system/tray/tray_utils.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/utf_string_conversions.h"
#include "components/session_manager/session_manager_types.h"
#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/base/ime/ash/extension_ime_util.h"
#include "ui/base/ime/ash/ime_bridge.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/range/range.h"
#include "ui/views/border.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/separator.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"

namespace ash {

namespace {

// Used for testing.
const int kEmojiButtonId = 1;
const int kSettingsButtonId = 2;
const int kVoiceButtonId = 3;

// Insets for the title view (dp).
constexpr auto kTitleViewPadding =
    gfx::Insets::VH(0, kMenuEdgeEffectivePadding);

// Insets for the bubble view to fix the overlapping
// between the floating menu and the IME tray in kiosk session (dp).
constexpr auto kKioskBubbleViewPadding = gfx::Insets::TLBR(-19, 0, 27, 0);

// The scroll view has no margin when the bottom buttons are shown at the top or
// bottom to make it flush with the header and footer.
constexpr auto kQsScrollViewMargin = gfx::Insets::TLBR(0, 16, 0, 16);

// When the bottom buttons are not shown (e.g Lockscreen) we need to have a 16px
// inset on the bottom in addition to the existing insets.
constexpr auto kQsScrollViewMarginWithoutBottomButtons =
    gfx::Insets::TLBR(0, 16, 16, 16);

// Returns the height range of ImeListView.
gfx::Range GetImeListViewRange() {
  const int max_items = 5;
  const int min_items = 1;
  const int tray_item_height = kTrayPopupItemMinHeight;
  // Insets at the top and bottom of the RoundedContainer.
  const int insets = RoundedContainer::kBorderInsets.top() +
                     RoundedContainer::kBorderInsets.bottom();
  return gfx::Range(tray_item_height * min_items + insets,
                    tray_item_height * max_items + insets);
}

// Returns true if the current screen is login or lock screen.
bool IsInLoginOrLockScreen() {
  using session_manager::SessionState;
  SessionState state = Shell::Get()->session_controller()->GetSessionState();
  return state == SessionState::LOGIN_PRIMARY ||
         state == SessionState::LOCKED ||
         state == SessionState::LOGIN_SECONDARY;
}

// Returns true if the current input context type is password.
bool IsInPasswordInputContext() {
  return IMEBridge::Get()->GetCurrentInputContext().type ==
         ui::TEXT_INPUT_TYPE_PASSWORD;
}

// Returns true if it is Kiosk Session.
bool IsKioskSession() {
  return Shell::Get()->session_controller()->IsRunningInAppMode();
}

bool ShouldShowVoiceButton() {
  auto* ime_controller = Shell::Get()->ime_controller();
  const bool is_dictation_enabled =
      Shell::Get()
          ->accessibility_controller()
          ->GetFeature(A11yFeatureType::kDictation)
          .enabled();

  // Only enable voice button in IME tray if the function is enabled and
  // the accessibility dictation is not enabled in the shelf.
  return ime_controller->is_voice_enabled() && !is_dictation_enabled;
}

// Returns true if the menu should show emoji, handwriting and voice buttons
// on the bottom.
bool ShouldShowBottomButtons() {
  // Emoji, handwriting and voice input is not supported for these cases:
  // 1) third party IME extensions.
  // 2) login/lock screen.
  // 3) password input client.
  auto* ime_controller = Shell::Get()->ime_controller();
  bool bottom_buttons_enabled =
      ime_controller->is_extra_input_options_enabled() &&
      !ime_controller->current_ime().third_party && !IsInLoginOrLockScreen() &&
      !IsInPasswordInputContext();
  if (!bottom_buttons_enabled) {
    return false;
  }

  return ime_controller->is_emoji_enabled() ||
         ime_controller->is_handwriting_enabled() || ShouldShowVoiceButton();
}

class ImeMenuLabel : public views::Label {
  METADATA_HEADER(ImeMenuLabel, views::Label)

 public:
  ImeMenuLabel() {
    // Sometimes the label will be more than 2 characters, e.g. INTL and EXTD.
    // This border makes sure we only leave room for ~2 and the others are
    // truncated.
    SetBorder(views::CreateEmptyBorder(gfx::Insets::VH(0, 6)));
  }
  ImeMenuLabel(const ImeMenuLabel&) = delete;
  ImeMenuLabel& operator=(const ImeMenuLabel&) = delete;
  ~ImeMenuLabel() override = default;

  // views:Label:
  gfx::Size CalculatePreferredSize(
      const views::SizeBounds& available_size) const override {
    return gfx::Size(kTrayItemSize, kTrayItemSize);
  }
};

BEGIN_METADATA(ImeMenuLabel)
END_METADATA

class ImeMenuImageView : public views::ImageView {
  METADATA_HEADER(ImeMenuImageView, views::ImageView)

 public:
  ImeMenuImageView() {
    SetBorder(views::CreateEmptyBorder(gfx::Insets::VH(0, 6)));
  }
  ImeMenuImageView(const ImeMenuImageView&) = delete;
  ImeMenuImageView& operator=(const ImeMenuImageView&) = delete;
  ~ImeMenuImageView() override = default;
};

BEGIN_METADATA(ImeMenuImageView)
END_METADATA

// The view that contains IME menu title.
class ImeTitleView : public views::BoxLayoutView {
  METADATA_HEADER(ImeTitleView, views::BoxLayoutView)

 public:
  ImeTitleView() {
    SetID(VIEW_ID_IME_TITLE_VIEW);
    SetOrientation(views::BoxLayout::Orientation::kHorizontal);
    SetInsideBorderInsets(kTitleViewPadding);
    SetMinimumCrossAxisSize(kTrayPopupItemMinHeight);
    SetCrossAxisAlignment(views::BoxLayout::CrossAxisAlignment::kCenter);

    auto* title_label = AddChildView(std::make_unique<views::Label>(
        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME)));
    title_label->SetBorder(
        views::CreateEmptyBorder(gfx::Insets::TLBR(0, 0, 1, 0)));
    title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    title_label->SetEnabledColorId(kColorAshTextColorPrimary);
    title_label->SetAutoColorReadabilityEnabled(false);
    TypographyProvider::Get()->StyleLabel(TypographyToken::kCrosTitle1,
                                          *title_label);
    SetFlexForView(title_label, 1);

    // Don't create Settings Button if it is Kiosk session.
    if (!IsKioskSession()) {
      settings_button_ = AddChildView(std::make_unique<IconButton>(
          base::BindRepeating([]() {
            base::RecordAction(
                base::UserMetricsAction("StatusArea_IME_Detailed"));
            Shell::Get()->system_tray_model()->client()->ShowIMESettings();
          }),
          IconButton::Type::kMedium, &kSystemMenuSettingsIcon,
          IDS_ASH_STATUS_TRAY_IME_SETTINGS));
      settings_button_->SetEnabled(TrayPopupUtils::CanOpenWebUISettings());
      settings_button_->SetID(kSettingsButtonId);
    }
  }
  ImeTitleView(const ImeTitleView&) = delete;
  ImeTitleView& operator=(const ImeTitleView&) = delete;

  ~ImeTitleView() override = default;

 private:
  raw_ptr<IconButton> settings_button_ = nullptr;
};

BEGIN_METADATA(ImeTitleView)
END_METADATA

// The view that contains buttons shown on the bottom of IME menu.
class ImeButtonsView : public views::View {
  METADATA_HEADER(ImeButtonsView, views::View)

 public:
  ImeButtonsView(ImeMenuTray* ime_menu_tray,
                 bool show_emoji,
                 bool show_handwriting,
                 bool show_voice)
      : ime_menu_tray_(ime_menu_tray) {
    DCHECK(ime_menu_tray_);
    SetID(VIEW_ID_IME_BUTTONS_VIEW);
    Init(show_emoji, show_handwriting, show_voice);
  }
  ImeButtonsView(const ImeButtonsView&) = delete;
  ImeButtonsView& operator=(const ImeButtonsView&) = delete;

  ~ImeButtonsView() override = default;

  void KeysetButtonPressed(input_method::ImeKeyset keyset) {
    // TODO(dcheng): When https://crbug.com/742517 is fixed, Mojo will
    // generate a constant for the number of values in the enum. For now, we
    // just define it here and keep it in sync with the enum.
    const int kImeKeysetUmaBoundary = 4;
    UMA_HISTOGRAM_ENUMERATION("InputMethod.ImeMenu.EmojiHandwritingVoiceButton",
                              keyset, kImeKeysetUmaBoundary);

    // The |keyset| will be used for drawing input view keyset in IME
    // extensions. ImeMenuTray::ShowKeyboardWithKeyset() will deal with
    // the |keyset| string to generate the right input view url.
    ime_menu_tray_->ShowKeyboardWithKeyset(keyset);
  }

 private:
  void Init(bool show_emoji, bool show_handwriting, bool show_voice) {
    auto box_layout = std::make_unique<views::BoxLayout>(
        views::BoxLayout::Orientation::kHorizontal);
    box_layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight);
    SetLayoutManager(std::move(box_layout));
    SetBorder(views::CreateEmptyBorder(
        gfx::Insets::VH(0, kMenuExtraMarginFromLeftEdge)));
    if (show_emoji) {
      emoji_button_ = new SystemMenuButton(
          base::BindRepeating(&ImeButtonsView::KeysetButtonPressed,
                              base::Unretained(this),
                              input_method::ImeKeyset::kEmoji),
          kImeMenuEmoticonIcon, IDS_ASH_STATUS_TRAY_IME_EMOJI);
      emoji_button_->SetID(kEmojiButtonId);
      AddChildView(emoji_button_.get());
    }

    if (show_handwriting) {
      handwriting_button_ = new SystemMenuButton(
          base::BindRepeating(&ImeButtonsView::KeysetButtonPressed,
                              base::Unretained(this),
                              input_method::ImeKeyset::kHandwriting),
          kImeMenuWriteIcon, IDS_ASH_STATUS_TRAY_IME_HANDWRITING);
      AddChildView(handwriting_button_.get());
    }

    if (show_voice) {
      voice_button_ = new SystemMenuButton(
          base::BindRepeating(&ImeButtonsView::KeysetButtonPressed,
                              base::Unretained(this),
                              input_method::ImeKeyset::kVoice),
          kImeMenuMicrophoneIcon, IDS_ASH_STATUS_TRAY_IME_VOICE);
      voice_button_->SetID(kVoiceButtonId);
      AddChildView(voice_button_.get());
    }
  }

  raw_ptr<ImeMenuTray, DanglingUntriaged> ime_menu_tray_;
  raw_ptr<SystemMenuButton> emoji_button_;
  raw_ptr<SystemMenuButton> handwriting_button_;
  raw_ptr<SystemMenuButton> voice_button_;
};

BEGIN_METADATA(ImeButtonsView)
END_METADATA

// A list of available IMEs shown in the opt-in IME menu, which has a
// different height depending on the number of IMEs in the list.
class ImeMenuListView : public ImeListView {
  METADATA_HEADER(ImeMenuListView, ImeListView)

 public:
  ImeMenuListView() : ImeMenuListView(std::make_unique<Delegate>()) {
    SetID(VIEW_ID_IME_MENU_LIST_VIEW);
  }
  ImeMenuListView(const ImeMenuListView&) = delete;
  ImeMenuListView& operator=(const ImeMenuListView&) = delete;

  ~ImeMenuListView() override = default;

 private:
  class Delegate : public DetailedViewDelegate {
   public:
    Delegate() : DetailedViewDelegate(nullptr /* tray_controller */) {}

    Delegate(const Delegate&) = delete;
    Delegate& operator=(const Delegate&) = delete;

    // DetailedViewDelegate:
    void TransitionToMainView(bool restore_focus) override {}
    void CloseBubble() override {}
    gfx::Insets GetScrollViewMargin() const override {
      return ShouldShowBottomButtons()
                 ? kQsScrollViewMargin
                 : kQsScrollViewMarginWithoutBottomButtons;
    }
  };

  explicit ImeMenuListView(std::unique_ptr<Delegate> delegate)
      : ImeListView(delegate.get()) {
    set_should_focus_ime_after_selection_with_keyboard(true);
    delegate_ = std::move(delegate);
  }

  // ImeListView:
  void Layout(PassKey) override {
    gfx::Range height_range = GetImeListViewRange();
    scroller()->ClipHeightTo(height_range.start(), height_range.end());
    LayoutSuperclass<ImeListView>(this);
  }

  std::unique_ptr<Delegate> delegate_;
};

BEGIN_METADATA(ImeMenuListView)
END_METADATA

}  // namespace

ImeMenuTray::ImeMenuTray(Shelf* shelf)
    : TrayBackgroundView(shelf, TrayBackgroundViewCatalogName::kImeMenu),
      ime_controller_(Shell::Get()->ime_controller()),
      label_(nullptr),
      image_view_(nullptr),
      keyboard_suppressed_(false),
      show_bubble_after_keyboard_hidden_(false),
      is_emoji_enabled_(false),
      is_handwriting_enabled_(false),
      is_voice_enabled_(false) {
  DCHECK(ime_controller_);
  SetCallback(base::BindRepeating(&ImeMenuTray::OnTrayButtonPressed,
                                  weak_ptr_factory_.GetWeakPtr()));
  CreateLabel();
  SystemTrayNotifier* tray_notifier = Shell::Get()->system_tray_notifier();
  tray_notifier->AddIMEObserver(this);
  tray_notifier->AddVirtualKeyboardObserver(this);

  // Show the tray even if virtual keyboard is shown. (Other tray buttons will
  // be hidden).
  set_show_with_virtual_keyboard(true);
}

ImeMenuTray::~ImeMenuTray() {
  if (bubble_) {
    bubble_->bubble_view()->ResetDelegate();
  }
  SystemTrayNotifier* tray_notifier = Shell::Get()->system_tray_notifier();
  tray_notifier->RemoveIMEObserver(this);
  tray_notifier->RemoveVirtualKeyboardObserver(this);
  auto* keyboard_controller = keyboard::KeyboardUIController::Get();
  if (keyboard_controller->HasObserver(this)) {
    keyboard_controller->RemoveObserver(this);
  }
}

void ImeMenuTray::OnTrayButtonPressed() {
  UserMetricsRecorder::RecordUserClickOnTray(
      LoginMetricsRecorder::TrayClickTarget::kImeTray);

  if (GetBubbleWidget()) {
    CloseBubble();
    return;
  }

  ShowBubble();
}

void ImeMenuTray::ShowImeMenuBubbleInternal() {
  TrayBubbleView::InitParams init_params = CreateInitParamsForTrayBubble(this);
  if (IsKioskSession()) {
    init_params.insets = kKioskBubbleViewPadding;
  }

  std::unique_ptr<TrayBubbleView> bubble_view =
      std::make_unique<TrayBubbleView>(init_params);

  // Add a title item with a separator on the top of the IME menu.
  bubble_view->AddChildView(std::make_unique<ImeTitleView>());

  // Adds IME list to the bubble.
  ime_list_view_ =
      bubble_view->AddChildView(std::make_unique<ImeMenuListView>());
  ime_list_view_->Init(ShouldShowKeyboardToggle(),
                       ImeListView::SHOW_SINGLE_IME);

  if (ShouldShowBottomButtons()) {
    auto* ime_controller = Shell::Get()->ime_controller();

    is_emoji_enabled_ = ime_controller->is_emoji_enabled();
    is_handwriting_enabled_ = ime_controller->is_handwriting_enabled();
    is_voice_enabled_ = ShouldShowVoiceButton();

    bubble_view->AddChildView(std::make_unique<ImeButtonsView>(
        this, is_emoji_enabled_, is_handwriting_enabled_, is_voice_enabled_));
  } else {
    is_emoji_enabled_ = is_handwriting_enabled_ = is_voice_enabled_ = false;
  }

  bubble_ = std::make_unique<TrayBubbleWrapper>(this);
  bubble_->ShowBubble(std::move(bubble_view));
  SetIsActive(true);

  Shell::Get()->system_tray_notifier()->NotifyImeMenuTrayBubbleShown();
}

void ImeMenuTray::ShowKeyboardWithKeyset(input_method::ImeKeyset keyset) {
  CloseBubble();

  // Show emoji in the same way as other means of opening and showing emoji
  // for laptop and tablet mode.
  if (keyset == input_method::ImeKeyset::kEmoji) {
    ui::ShowEmojiPanel();
  } else {
    Shell::Get()
        ->keyboard_controller()
        ->virtual_keyboard_controller()
        ->ForceShowKeyboardWithKeyset(keyset);
  }
}

bool ImeMenuTray::ShouldShowKeyboardToggle() const {
  return keyboard_suppressed_ && !Shell::Get()
                                      ->accessibility_controller()
                                      ->virtual_keyboard()
                                      .enabled();
}

void ImeMenuTray::OnThemeChanged() {
  TrayBackgroundView::OnThemeChanged();
  UpdateTrayLabel();
}

std::u16string ImeMenuTray::GetAccessibleNameForTray() {
  return l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME);
}

void ImeMenuTray::HandleLocaleChange() {
  if (image_view_) {
    image_view_->SetTooltipText(
        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME));
  }

  if (label_) {
    label_->SetTooltipText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME));
  }
}

void ImeMenuTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
  if (bubble_->bubble_view() == bubble_view) {
    CloseBubble();
  }
}

void ImeMenuTray::ClickedOutsideBubble(const ui::LocatedEvent& event) {
  CloseBubble();
}

void ImeMenuTray::UpdateTrayItemColor(bool is_active) {
  UpdateTrayImageOrLabelColor(
      extension_ime_util::IsArcIME(ime_controller_->current_ime().id));
}

void ImeMenuTray::CloseBubbleInternal() {
  bubble_.reset();
  ime_list_view_ = nullptr;
  SetIsActive(false);
  shelf()->UpdateAutoHideState();
}

void ImeMenuTray::ShowBubble() {
  auto* keyboard_controller = keyboard::KeyboardUIController::Get();
  if (keyboard_controller->IsKeyboardVisible()) {
    show_bubble_after_keyboard_hidden_ = true;
    keyboard_controller->AddObserver(this);
    keyboard_controller->HideKeyboardExplicitlyBySystem();
  } else {
    base::RecordAction(base::UserMetricsAction("Tray_ImeMenu_Opened"));
    ShowImeMenuBubbleInternal();
  }
}

TrayBubbleView* ImeMenuTray::GetBubbleView() {
  return bubble_ ? bubble_->GetBubbleView() : nullptr;
}

views::Widget* ImeMenuTray::GetBubbleWidget() const {
  return bubble_ ? bubble_->GetBubbleWidget() : nullptr;
}

void ImeMenuTray::AddedToWidget() {
  // SetVisiblePreferred cannot be called until after the view has been added to
  // a widget.
  auto* ime_controller = Shell::Get()->ime_controller();

  // On the primary display, `ImeMenuTray` is created for the primary shelf, and
  // then `ImeObserver`s (of which `ImeMenuTray` is one) can react to IME menu
  // activation. If the IME menu is active, and then a display is connected,
  // this object will not have been notified of previous IME menu activations.
  // So check for that here and modify visibility. Only necessary for secondary
  // displays.
  if (!ime_controller || !ime_controller->is_menu_active()) {
    return;
  }

  SetVisiblePreferred(true);
  UpdateTrayLabel();
}

void ImeMenuTray::OnIMERefresh() {
  UpdateTrayLabel();
  if (bubble_ && ime_list_view_) {
    ime_list_view_->Update(
        ime_controller_->current_ime().id, ime_controller_->GetVisibleImes(),
        ime_controller_->current_ime_menu_items(), ShouldShowKeyboardToggle(),
        ImeListView::SHOW_SINGLE_IME);
  }
}

void ImeMenuTray::OnIMEMenuActivationChanged(bool is_activated) {
  SetVisiblePreferred(is_activated);
  if (is_activated) {
    UpdateTrayLabel();
  } else {
    CloseBubble();
  }
}

std::u16string ImeMenuTray::GetAccessibleNameForBubble() {
  return l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME);
}

bool ImeMenuTray::ShouldEnableExtraKeyboardAccessibility() {
  return Shell::Get()->accessibility_controller()->spoken_feedback().enabled();
}

void ImeMenuTray::HideBubble(const TrayBubbleView* bubble_view) {
  HideBubbleWithView(bubble_view);
}

void ImeMenuTray::OnKeyboardHidden(bool is_temporary_hide) {
  if (show_bubble_after_keyboard_hidden_) {
    show_bubble_after_keyboard_hidden_ = false;
    auto* keyboard_controller = keyboard::KeyboardUIController::Get();
    keyboard_controller->RemoveObserver(this);

    ShowImeMenuBubbleInternal();
    return;
  }
}

void ImeMenuTray::OnKeyboardSuppressionChanged(bool suppressed) {
  if (suppressed != keyboard_suppressed_ && bubble_) {
    CloseBubble();
  }
  keyboard_suppressed_ = suppressed;
}

bool ImeMenuTray::AnyBottomButtonShownForTest() const {
  return is_emoji_enabled_ || is_handwriting_enabled_ || is_voice_enabled_;
}

void ImeMenuTray::UpdateTrayLabel() {
  const ImeInfo& current_ime = ime_controller_->current_ime();

  // For ARC IMEs, we use the globe icon instead of the short name of the active
  // IME.
  if (extension_ime_util::IsArcIME(current_ime.id)) {
    CreateImageView();
    UpdateTrayImageOrLabelColor(/*is_image=*/true);
    return;
  }

  // Updates the tray label based on the current input method.
  CreateLabel();
  UpdateTrayImageOrLabelColor(/*is_image=*/false);

  if (current_ime.third_party) {
    label_->SetText(current_ime.short_name + u"*");
  } else {
    label_->SetText(current_ime.short_name);
  }
}

void ImeMenuTray::CreateLabel() {
  // Do nothing if label_ is already created.
  if (label_) {
    return;
  }
  // Remove image_view_ at first if it's created.
  if (image_view_) {
    tray_container()->RemoveChildView(image_view_);
    image_view_ = nullptr;
  }
  label_ = new ImeMenuLabel();
  SetupLabelForTray(label_);
  label_->SetElideBehavior(gfx::TRUNCATE);
  label_->SetTooltipText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME));
  tray_container()->AddChildView(label_.get());
}

void ImeMenuTray::CreateImageView() {
  // Do nothing if image_view_ is already created.
  if (image_view_) {
    return;
  }
  // Remove label_ at first if it's created.
  if (label_) {
    tray_container()->RemoveChildView(label_);
    label_ = nullptr;
  }
  image_view_ = new ImeMenuImageView();
  image_view_->SetTooltipText(
      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME));
  tray_container()->AddChildView(image_view_.get());
}

void ImeMenuTray::UpdateTrayImageOrLabelColor(bool is_image) {
  const ui::ColorId color_id =
      is_active() ? cros_tokens::kCrosSysSystemOnPrimaryContainer
                  : cros_tokens::kCrosSysOnSurface;

  if (is_image) {
    image_view_->SetImage(
        ui::ImageModel::FromVectorIcon(kShelfGlobeIcon, color_id));
    return;
  }

  label_->SetEnabledColorId(color_id);
}

BEGIN_METADATA(ImeMenuTray)
END_METADATA

}  // namespace ash