1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/android/application_status_listener.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/callback_forward.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/run_loop.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/threading/thread.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace base {
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace android {
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::android::ScopedJavaLocalRef;
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// An invalid ApplicationState value.
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const ApplicationState kInvalidApplicationState =
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    static_cast<ApplicationState>(100);
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Used to generate a callback that stores the new state at a given location.
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void StoreStateTo(ApplicationState* target, ApplicationState state) {
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *target = state;
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void RunTasksUntilIdle() {
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RunLoop run_loop;
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  run_loop.RunUntilIdle();
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Shared state for the multi-threaded test.
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This uses a thread to register for events and listen to them, while state
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// changes are forced on the main thread.
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MultiThreadedTest {
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  MultiThreadedTest()
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      : state_(kInvalidApplicationState),
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        event_(false, false),
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        thread_("ApplicationStatusTest thread"),
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        main_() {
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void Run() {
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Start the thread and tell it to register for events.
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    thread_.Start();
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    thread_.message_loop()
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ->PostTask(FROM_HERE,
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              base::Unretained(this)));
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Wait for its completion.
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    event_.Wait();
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Change state, then wait for the thread to modify state.
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ApplicationStatusListener::NotifyApplicationStateChange(
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    event_.Wait();
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, state_);
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Again
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ApplicationStatusListener::NotifyApplicationStateChange(
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    event_.Wait();
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, state_);
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void ExpectOnThread() {
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_EQ(thread_.message_loop(), base::MessageLoop::current());
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void RegisterThreadForEvents() {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ExpectOnThread();
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    listener_.reset(new ApplicationStatusListener(base::Bind(
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        &MultiThreadedTest::StoreStateAndSignal, base::Unretained(this))));
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_TRUE(listener_.get());
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    event_.Signal();
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void StoreStateAndSignal(ApplicationState state) {
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ExpectOnThread();
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    state_ = state;
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    event_.Signal();
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ApplicationState state_;
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::WaitableEvent event_;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::Thread thread_;
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop main_;
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<ApplicationStatusListener> listener_;
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST(ApplicationStatusListenerTest, SingleThread) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  MessageLoop message_loop;
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ApplicationState result = kInvalidApplicationState;
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Create a new listener that stores the new state into |result| on every
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // state change.
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ApplicationStatusListener listener(
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&StoreStateTo, base::Unretained(&result)));
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(kInvalidApplicationState, result);
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ApplicationStatusListener::NotifyApplicationStateChange(
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RunTasksUntilIdle();
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, result);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ApplicationStatusListener::NotifyApplicationStateChange(
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RunTasksUntilIdle();
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, result);
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST(ApplicationStatusListenerTest, TwoThreads) {
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  MultiThreadedTest test;
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  test.Run();
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace android
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace base
131