15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/video_detector.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/test/ash_test_base.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/wm/window_state.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/wm/wm_event.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkColor.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/client/aura_constants.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/test/test_windows.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/wm/public/window_types.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace test {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation that just counts the number of times we've been told that a
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// video is playing.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestVideoDetectorObserver : public VideoDetectorObserver {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestVideoDetectorObserver() : num_invocations_(0),
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                num_fullscreens_(0),
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                num_not_fullscreens_(0) {}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_invocations() const { return num_invocations_; }
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_fullscreens() const { return num_fullscreens_; }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_not_fullscreens() const { return num_not_fullscreens_; }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void reset_stats() {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_invocations_ = 0;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_fullscreens_ = 0;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_not_fullscreens_ = 0;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // VideoDetectorObserver implementation.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnVideoDetected(bool is_fullscreen) OVERRIDE {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_invocations_++;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_fullscreen)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_fullscreens_++;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_not_fullscreens_++;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of times that OnVideoDetected() has been called.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_invocations_;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of times that OnVideoDetected() has been called with is_fullscreen
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // == true.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_fullscreens_;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of times that OnVideoDetected() has been called with is_fullscreen
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // == false.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_not_fullscreens_;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestVideoDetectorObserver);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VideoDetectorTest : public AshTestBase {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VideoDetectorTest() {}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~VideoDetectorTest() {}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AshTestBase::SetUp();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_.reset(new TestVideoDetectorObserver);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detector_ = Shell::GetInstance()->video_detector();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detector_->AddObserver(observer_.get());
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    now_ = base::TimeTicks::Now();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detector_->set_now_for_test(now_);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TearDown() OVERRIDE {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detector_->RemoveObserver(observer_.get());
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AshTestBase::TearDown();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move |detector_|'s idea of the current time forward by |delta|.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AdvanceTime(base::TimeDelta delta) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    now_ += delta;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detector_->set_now_for_test(now_);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VideoDetector* detector_;  // not owned
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<TestVideoDetectorObserver> observer_;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now_;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VideoDetectorTest);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(VideoDetectorTest, Basic) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<aura::Window> window(
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateTestWindowInShell(SK_ColorRED, 12345, window_bounds));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send enough updates, but make them be too small to trigger detection.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect update_region(
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Point(),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Size(VideoDetector::kMinUpdateWidth - 1,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                VideoDetector::kMinUpdateHeight));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_invocations());
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send not-quite-enough adaquately-sized updates.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_->reset_stats();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromSeconds(2));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_region.set_size(
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Size(VideoDetector::kMinUpdateWidth,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                VideoDetector::kMinUpdateHeight));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond - 1; ++i)
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_invocations());
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should get notified after the next update, but not in response to
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // additional updates.
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  detector_->OnDelegatedFrameDamage(window.get(), update_region);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_fullscreens());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_not_fullscreens());
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  detector_->OnDelegatedFrameDamage(window.get(), update_region);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_fullscreens());
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_not_fullscreens());
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Spread out the frames over a longer period of time, but send enough
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // over a one-second window that the observer should be notified.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_->reset_stats();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromSeconds(2));
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  detector_->OnDelegatedFrameDamage(window.get(), update_region);
141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_invocations());
142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
143a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromMilliseconds(500));
144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  const int kNumFrames = VideoDetector::kMinFramesPerSecond + 1;
145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::TimeDelta kInterval =
146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(1000 / kNumFrames);
147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (int i = 0; i < kNumFrames; ++i) {
148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    AdvanceTime(kInterval);
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Keep going and check that the observer is notified again.
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (int i = 0; i < kNumFrames; ++i) {
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    AdvanceTime(kInterval);
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  EXPECT_EQ(2, observer_->num_invocations());
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Send updates at a slower rate and check that the observer isn't notified.
161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::TimeDelta kSlowInterval = base::TimeDelta::FromMilliseconds(
162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      1000 / (VideoDetector::kMinFramesPerSecond - 2));
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (int i = 0; i < kNumFrames; ++i) {
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    AdvanceTime(kSlowInterval);
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  EXPECT_EQ(2, observer_->num_invocations());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(VideoDetectorTest, Shutdown) {
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768));
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<aura::Window> window(
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CreateTestWindowInShell(SK_ColorRED, 12345, window_bounds));
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Rect update_region(
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      gfx::Point(),
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      gfx::Size(VideoDetector::kMinUpdateWidth,
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                VideoDetector::kMinUpdateHeight));
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // It should not detect video during the shutdown.
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Shell::GetInstance()->OnAppTerminating();
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(0, observer_->num_invocations());
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(VideoDetectorTest, WindowNotVisible) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768));
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<aura::Window> window(
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateTestWindowInShell(SK_ColorRED, 12345, window_bounds));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reparent the window to the root to make sure that visibility changes aren't
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // animated.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shell::GetPrimaryRootWindow()->AddChild(window.get());
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We shouldn't report video that's played in a hidden window.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->Hide();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect update_region(
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Point(),
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Size(VideoDetector::kMinUpdateWidth,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                VideoDetector::kMinUpdateHeight));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_invocations());
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make the window visible and send more updates.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_->reset_stats();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromSeconds(2));
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->Show();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_fullscreens());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_not_fullscreens());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We also shouldn't report video in a window that's fully offscreen.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_->reset_stats();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromSeconds(2));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect offscreen_bounds(
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Point(Shell::GetPrimaryRootWindow()->bounds().width(), 0),
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_bounds.size());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->SetBounds(offscreen_bounds);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(offscreen_bounds, window->bounds());
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_invocations());
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(VideoDetectorTest, MultipleWindows) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create two windows.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<aura::Window> window1(
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateTestWindowInShell(SK_ColorRED, 12345, window_bounds));
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<aura::Window> window2(
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateTestWindowInShell(SK_ColorBLUE, 23456, window_bounds));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Even if there's video playing in both, the observer should only receive a
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // single notification.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect update_region(
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Point(),
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Size(VideoDetector::kMinUpdateWidth,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                VideoDetector::kMinUpdateHeight));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window1.get(), update_region);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window2.get(), update_region);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_fullscreens());
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_not_fullscreens());
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that the observer receives repeated notifications.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(VideoDetectorTest, RepeatedNotifications) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect window_bounds(gfx::Point(), gfx::Size(1024, 768));
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<aura::Window> window(
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateTestWindowInShell(SK_ColorRED, 12345, window_bounds));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect update_region(
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Point(),
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Size(VideoDetector::kMinUpdateWidth,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                VideoDetector::kMinUpdateHeight));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_fullscreens());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_not_fullscreens());
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let enough time pass that a second notification should be sent.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_->reset_stats();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromSeconds(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int64>(VideoDetector::kNotifyIntervalSec + 1)));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), update_region);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_fullscreens());
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_not_fullscreens());
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that the observer receives a true value when the window is fullscreen.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(VideoDetectorTest, FullscreenWindow) {
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!SupportsMultipleDisplays())
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UpdateDisplay("1024x768,1024x768");
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Rect kLeftBounds(gfx::Point(), gfx::Size(1024, 768));
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<aura::Window> window(
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CreateTestWindowInShell(SK_ColorRED, 12345, kLeftBounds));
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  wm::WindowState* window_state = wm::GetWindowState(window.get());
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  window_state->OnWMEvent(&toggle_fullscreen_event);
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_TRUE(window_state->IsFullscreen());
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->Focus();
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Rect kUpdateRegion(
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Point(),
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Size(VideoDetector::kMinUpdateWidth,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                VideoDetector::kMinUpdateHeight));
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), kUpdateRegion);
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_fullscreens());
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_not_fullscreens());
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make the first window non-fullscreen and open a second fullscreen window on
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // a different desktop.
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  window_state->OnWMEvent(&toggle_fullscreen_event);
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_FALSE(window_state->IsFullscreen());
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Rect kRightBounds(gfx::Point(1024, 0), gfx::Size(1024, 768));
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<aura::Window> other_window(
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CreateTestWindowInShell(SK_ColorBLUE, 6789, kRightBounds));
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  wm::WindowState* other_window_state = wm::GetWindowState(other_window.get());
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  other_window_state->OnWMEvent(&toggle_fullscreen_event);
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_TRUE(other_window_state->IsFullscreen());
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // When video is detected in the first (now non-fullscreen) window, fullscreen
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // video should still be reported due to the second window being fullscreen.
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This avoids situations where non-fullscreen video could be reported when
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // multiple videos are playing in fullscreen and non-fullscreen windows.
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  observer_->reset_stats();
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromSeconds(2));
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), kUpdateRegion);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_fullscreens());
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_not_fullscreens());
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make the second window non-fullscreen and check that the next video report
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // is non-fullscreen.
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  other_window_state->OnWMEvent(&toggle_fullscreen_event);
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_FALSE(other_window_state->IsFullscreen());
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  observer_->reset_stats();
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AdvanceTime(base::TimeDelta::FromSeconds(2));
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < VideoDetector::kMinFramesPerSecond; ++i)
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    detector_->OnDelegatedFrameDamage(window.get(), kUpdateRegion);
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_invocations());
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, observer_->num_fullscreens());
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(1, observer_->num_not_fullscreens());
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace test
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
340