// 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/wm/video_detector.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/time.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/aura/client/window_types.h" #include "ui/aura/root_window.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h" #include "ui/gfx/rect.h" namespace ash { namespace test { // Implementation that just counts the number of times we've been told that a // video is playing. class TestVideoDetectorObserver : public VideoDetectorObserver { public: TestVideoDetectorObserver() : num_invocations_(0) {} int num_invocations() const { return num_invocations_; } void reset_stats() { num_invocations_ = 0; } // VideoDetectorObserver implementation. virtual void OnVideoDetected() OVERRIDE { num_invocations_++; } private: // Number of times that OnVideoDetected() has been called. int num_invocations_; DISALLOW_COPY_AND_ASSIGN(TestVideoDetectorObserver); }; class VideoDetectorTest : public AshTestBase { public: VideoDetectorTest() {} virtual ~VideoDetectorTest() {} void SetUp() OVERRIDE { AshTestBase::SetUp(); observer_.reset(new TestVideoDetectorObserver); detector_ = Shell::GetInstance()->video_detector(); detector_->AddObserver(observer_.get()); now_ = base::TimeTicks::Now(); detector_->set_now_for_test(now_); } protected: // Move |detector_|'s idea of the current time forward by |delta|. void AdvanceTime(base::TimeDelta delta) { now_ += delta; detector_->set_now_for_test(now_); } VideoDetector* detector_; // not owned scoped_ptr observer_; base::TimeTicks now_; private: DISALLOW_COPY_AND_ASSIGN(VideoDetectorTest); }; TEST_F(VideoDetectorTest, Basic) { gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768)); scoped_ptr window( aura::test::CreateTestWindow(SK_ColorRED, 12345, window_bounds, NULL)); // Send enough updates, but make them be too small to trigger detection. gfx::Rect update_region( gfx::Point(), gfx::Size(VideoDetector::kMinUpdateWidth - 1, VideoDetector::kMinUpdateHeight)); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(0, observer_->num_invocations()); // Send not-quite-enough adaquately-sized updates. observer_->reset_stats(); AdvanceTime(base::TimeDelta::FromSeconds(2)); update_region.set_size( gfx::Size(VideoDetector::kMinUpdateWidth, VideoDetector::kMinUpdateHeight)); for (int i = 0; i < VideoDetector::kMinFramesPerSecond - 1; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(0, observer_->num_invocations()); // We should get notified after the next update, but not in response to // additional updates. detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(1, observer_->num_invocations()); detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(1, observer_->num_invocations()); // Spread out the frames over two seconds; we shouldn't detect video. observer_->reset_stats(); AdvanceTime(base::TimeDelta::FromSeconds(2)); for (int i = 0; i < VideoDetector::kMinFramesPerSecond - 1; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); AdvanceTime(base::TimeDelta::FromSeconds(1)); for (int i = 0; i < VideoDetector::kMinFramesPerSecond - 1; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(0, observer_->num_invocations()); } TEST_F(VideoDetectorTest, WindowNotVisible) { gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768)); scoped_ptr window( aura::test::CreateTestWindow(SK_ColorRED, 12345, window_bounds, NULL)); // Reparent the window to the root to make sure that visibility changes aren't // animated. Shell::GetRootWindow()->AddChild(window.get()); // We shouldn't report video that's played in a hidden window. window->Hide(); gfx::Rect update_region( gfx::Point(), gfx::Size(VideoDetector::kMinUpdateWidth, VideoDetector::kMinUpdateHeight)); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(0, observer_->num_invocations()); // Make the window visible and send more updates. observer_->reset_stats(); AdvanceTime(base::TimeDelta::FromSeconds(2)); window->Show(); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(1, observer_->num_invocations()); // We also shouldn't report video in a window that's fully offscreen. observer_->reset_stats(); AdvanceTime(base::TimeDelta::FromSeconds(2)); gfx::Rect offscreen_bounds( gfx::Point(Shell::GetRootWindow()->bounds().width(), 0), window_bounds.size()); window->SetBounds(offscreen_bounds); ASSERT_EQ(offscreen_bounds, window->bounds()); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(0, observer_->num_invocations()); } TEST_F(VideoDetectorTest, MultipleWindows) { // Create two windows. gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768)); scoped_ptr window1( aura::test::CreateTestWindow(SK_ColorRED, 12345, window_bounds, NULL)); scoped_ptr window2( aura::test::CreateTestWindow(SK_ColorBLUE, 23456, window_bounds, NULL)); // Even if there's video playing in both, the observer should only receive a // single notification. gfx::Rect update_region( gfx::Point(), gfx::Size(VideoDetector::kMinUpdateWidth, VideoDetector::kMinUpdateHeight)); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window1.get(), update_region); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window2.get(), update_region); EXPECT_EQ(1, observer_->num_invocations()); } // Test that the observer receives repeated notifications. TEST_F(VideoDetectorTest, RepeatedNotifications) { gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768)); scoped_ptr window( aura::test::CreateTestWindow(SK_ColorRED, 12345, window_bounds, NULL)); gfx::Rect update_region( gfx::Point(), gfx::Size(VideoDetector::kMinUpdateWidth, VideoDetector::kMinUpdateHeight)); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(1, observer_->num_invocations()); // Let enough time pass that a second notification should be sent. observer_->reset_stats(); AdvanceTime(base::TimeDelta::FromSeconds( static_cast(VideoDetector::kNotifyIntervalSec + 1))); for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i) detector_->OnWindowPaintScheduled(window.get(), update_region); EXPECT_EQ(1, observer_->num_invocations()); } } // namespace test } // namespace ash