chromium/chromecast/browser/cast_content_window_aura.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/browser/cast_content_window_aura.h"

#include <memory>

#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "chromecast/chromecast_buildflags.h"
#include "chromecast/graphics/cast_window_manager.h"
#include "content/public/browser/web_contents.h"
#include "ui/aura/window.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"

namespace chromecast {

namespace {

CastGestureHandler::Priority ToGestureHandlerPriority(
    mojom::GesturePriority priority) {
  switch (priority) {
    case mojom::GesturePriority::NONE:
      return CastGestureHandler::Priority::NONE;
    case mojom::GesturePriority::ROOT_UI:
      return CastGestureHandler::Priority::ROOT_UI;
    case mojom::GesturePriority::MAIN_ACTIVITY:
      return CastGestureHandler::Priority::MAIN_ACTIVITY;
    case mojom::GesturePriority::SETTINGS_UI:
      return CastGestureHandler::Priority::SETTINGS_UI;
  }
}

}  // namespace
class TouchBlocker : public ui::EventHandler, public aura::WindowObserver {
 public:
  TouchBlocker(aura::Window* window, bool activated)
      : window_(window), activated_(activated) {
    DCHECK(window_);
    window_->AddObserver(this);
    if (activated_) {
      window_->AddPreTargetHandler(this);
    }
  }

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

  ~TouchBlocker() override {
    if (window_) {
      window_->RemoveObserver(this);
      if (activated_) {
        window_->RemovePreTargetHandler(this);
      }
    }
  }

  void Activate(bool activate) {
    if (!window_ || activate == activated_) {
      return;
    }

    if (activate) {
      window_->AddPreTargetHandler(this);
    } else {
      window_->RemovePreTargetHandler(this);
    }

    activated_ = activate;
  }

 private:
  // Overriden from ui::EventHandler.
  void OnTouchEvent(ui::TouchEvent* touch) override {
    if (activated_) {
      touch->SetHandled();
    }
  }

  // Overriden from aura::WindowObserver.
  void OnWindowDestroyed(aura::Window* window) override { window_ = nullptr; }

  aura::Window* window_;
  bool activated_;
};

CastContentWindowAura::CastContentWindowAura(mojom::CastWebViewParamsPtr params,
                                             CastWindowManager* window_manager)
    : CastContentWindow(std::move(params)),
      window_manager_(window_manager),
      gesture_dispatcher_(
          std::make_unique<CastContentGestureHandler>(gesture_router())),
      window_(nullptr),
      has_screen_access_(false),
      resize_window_when_navigation_starts_(true) {}

CastContentWindowAura::~CastContentWindowAura() {
  content::WebContentsObserver::Observe(nullptr);
  CastWebContentsObserver::Observe(nullptr);
  if (window_manager_) {
    window_manager_->RemoveGestureHandler(gesture_dispatcher_.get());
  }
  if (window_) {
    window_->RemoveObserver(this);
  }
}

void CastContentWindowAura::CreateWindow(
    mojom::ZOrder z_order,
    VisibilityPriority visibility_priority) {
  DCHECK(window_manager_) << "A CastWindowManager must be provided before "
                          << "creating a window for WebContents.";
  CastWebContentsObserver::Observe(cast_web_contents());
  content::WebContentsObserver::Observe(WebContents());
  window_ = WebContents()->GetNativeView();
  if (!window_->HasObserver(this)) {
    window_->AddObserver(this);
  }
  window_manager_->SetZOrder(window_, z_order);
  window_manager_->AddWindow(window_);
  window_manager_->AddGestureHandler(gesture_dispatcher_.get());

  touch_blocker_ =
      std::make_unique<TouchBlocker>(window_, !params_->enable_touch_input);

  if (has_screen_access_) {
    window_->Show();
  } else {
    window_->Hide();
  }

  cast_web_contents()->web_contents()->Focus();
}

void CastContentWindowAura::GrantScreenAccess() {
  has_screen_access_ = true;
  if (window_) {
    SetFullWindowBounds();
    window_->Show();
  }
}

void CastContentWindowAura::RevokeScreenAccess() {
  has_screen_access_ = false;
  resize_window_when_navigation_starts_ = false;
  if (window_) {
    window_->Hide();
    SetHiddenWindowBounds();
  }
}

void CastContentWindowAura::EnableTouchInput(bool enabled) {
  if (touch_blocker_) {
    touch_blocker_->Activate(!enabled);
  }
}

void CastContentWindowAura::RequestVisibility(
    VisibilityPriority visibility_priority) {}

void CastContentWindowAura::OnWindowVisibilityChanged(aura::Window* window,
                                                      bool visible) {
  if (visible) {
    gesture_dispatcher_->SetPriority(
        ToGestureHandlerPriority(params_->gesture_priority));
  } else {
    gesture_dispatcher_->SetPriority(CastGestureHandler::Priority::NONE);
  }
}

void CastContentWindowAura::OnWindowDestroyed(aura::Window* window) {
  window_ = nullptr;
}

void CastContentWindowAura::DidStartNavigation(
    content::NavigationHandle* navigation_handle) {
  if (!resize_window_when_navigation_starts_ || !window_) {
    return;
  }
  resize_window_when_navigation_starts_ = false;
  SetFullWindowBounds();
}

void CastContentWindowAura::SetFullWindowBounds() {
#if !BUILDFLAG(IS_CAST_AUDIO_ONLY)
  gfx::Size display_size =
      display::Screen::GetScreen()->GetPrimaryDisplay().size();
  window_->SetBounds(gfx::Rect(display_size.width(), display_size.height()));
#endif
}

void CastContentWindowAura::SetHiddenWindowBounds() {
  // Because rendering a larger window may require more system resources,
  // resize the window to one pixel while hidden.
  LOG(INFO) << "Resizing window to 1x1 pixel while hidden";
  window_->SetBounds(gfx::Rect(1, 1));
}

}  // namespace chromecast