text: // Copyright 2017 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/wm/lock_action_handler_layout_manager.h"
  
  #include <utility>
  #include <vector>
  
  #include "ash/public/cpp/shell_window_ids.h"
  #include "ash/public/mojom/tray_action.mojom.h"
  #include "ash/shell.h"
  #include "ash/wm/lock_window_state.h"
  #include "ash/wm/window_state.h"
  #include "ash/wm/window_util.h"
  #include "ash/wm/wm_event.h"
  #include "base/bind.h"
  #include "ui/wm/core/window_animations.h"
  
  namespace ash {
  
  namespace {
  
  // Whether child windows should be shown depending on lock screen note action
  // state and lock screen action background state.
  // This should not be used for lock screen background windows.
  bool ShowChildWindows(mojom::TrayActionState action_state,
                        LockScreenActionBackgroundState background_state) {
    return (action_state == mojom::TrayActionState::kActive ||
            action_state == mojom::TrayActionState::kLaunching) &&
           (background_state == LockScreenActionBackgroundState::kShown ||
            background_state == LockScreenActionBackgroundState::kHidden);
  }
  
  }  // namespace
  
  LockActionHandlerLayoutManager::LockActionHandlerLayoutManager(
      aura::Window* window,
      Shelf* shelf,
      LockScreenActionBackgroundController* action_background_controller)
      : LockLayoutManager(window, shelf),
        action_background_controller_(action_background_controller) {
    TrayAction* tray_action = Shell::Get()->tray_action();
    tray_action_observation_.Observe(tray_action);
    action_background_observation_.Observe(action_background_controller_);
  }
  
  LockActionHandlerLayoutManager::~LockActionHandlerLayoutManager() = default;
  
  void LockActionHandlerLayoutManager::OnWindowAddedToLayout(
      aura::Window* child) {
    ::wm::SetWindowVisibilityAnimationTransition(child, ::wm::ANIMATE_NONE);
  
    // The lock action background should be shown behind the shelf (which is
    // transparent on the lock screen), unlike lock action handler windows.
    WindowState* window_state =
        action_background_controller_->IsBackgroundWindow(child)
            ? LockWindowState::SetLockWindowState(child)
            : LockWindowState::SetLockWindowStateWithShelfExcluded(child);
    WMEvent event(WM_EVENT_ADDED_TO_WORKSPACE);
    window_state->OnWMEvent(&event);
  }
  
  void LockActionHandlerLayoutManager::OnChildWindowVisibilityChanged(
      aura::Window* child,
      bool visible) {
    if (action_background_controller_->IsBackgroundWindow(child)) {
      window()->StackChildAtBottom(child);
      return;
    }
  
    // Windows should be shown only in active state.
    if (visible &&
        !ShowChildWindows(Shell::Get()->tray_action()->GetLockScreenNoteState(),
                          action_background_controller_->state())) {
      child->Hide();
    }
  }
  
  void LockActionHandlerLayoutManager::OnLockScreenNoteStateChanged(
      mojom::TrayActionState state) {
    // Update the background controller state first.
    bool background_changed = false;
    switch (state) {
      case mojom::TrayActionState::kNotAvailable:
        background_changed =
            action_background_controller_->HideBackgroundImmediately();
        break;
      case mojom::TrayActionState::kAvailable:
        background_changed = action_background_controller_->HideBackground();
        break;
      case mojom::TrayActionState::kLaunching:
      case mojom::TrayActionState::kActive:
        background_changed = action_background_controller_->ShowBackground();
        break;
    }
  
    // Given that background state changes invoke the background controller
    // observers (one of which is |this|), and |UpdateChildren| is called as part
    // of handling background state changes, the child windows state has alreday
    // been updated if |background_changed| is true - no need to do it again.
    if (background_changed)
      return;
  
    UpdateChildren(state, action_background_controller_->state());
  }
  
  void LockActionHandlerLayoutManager::OnLockScreenActionBackgroundStateChanged(
      LockScreenActionBackgroundState state) {
    UpdateChildren(Shell::Get()->tray_action()->GetLockScreenNoteState(), state);
  }
  
  void LockActionHandlerLayoutManager::UpdateChildren(
      mojom::TrayActionState action_state,
      LockScreenActionBackgroundState background_state) {
    // Update children state:
    // * a child can be visible only in active state
    // * on transition to active state:
    //     * show hidden windows, so children that were added when action was not
    //       in active state are shown
    //     * activate a container child to ensure the container gets focus when
    //       moving from background state.
    bool show_children = ShowChildWindows(action_state, background_state);
    aura::Window* child_to_activate = nullptr;
    for (aura::Window* child : window()->children()) {
      if (action_background_controller_->IsBackgroundWindow(child))
        continue;
      if (show_children) {
        child->Show();
        child_to_activate = child;
      } else {
        child->Hide();
      }
    }
  
    if (child_to_activate)
      wm::ActivateWindow(child_to_activate);
  }
  
  }  // namespace ash
  