1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
base / android / application_status_listener.cc [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/application_status_listener.h"
#include <jni.h>
#include "base/functional/callback.h"
#include "base/lazy_instance.h"
#include "base/metrics/user_metrics.h"
#include "base/observer_list_threadsafe.h"
#include "base/trace_event/base_tracing.h"
#if BUILDFLAG(ENABLE_BASE_TRACING)
#include "base/trace_event/application_state_proto_android.h" // no-presubmit-check
#endif // BUILDFLAG(ENABLE_BASE_TRACING)
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/tasks_jni/ApplicationStatus_jni.h"
namespace base {
namespace android {
namespace {
class ApplicationStatusListenerImpl;
struct LeakyLazyObserverListTraits
: base::internal::LeakyLazyInstanceTraits<
ObserverListThreadSafe<ApplicationStatusListenerImpl>> {
static ObserverListThreadSafe<ApplicationStatusListenerImpl>* New(
void* instance) {
ObserverListThreadSafe<ApplicationStatusListenerImpl>* ret =
base::internal::LeakyLazyInstanceTraits<ObserverListThreadSafe<
ApplicationStatusListenerImpl>>::New(instance);
// Leaky.
ret->AddRef();
return ret;
}
};
LazyInstance<ObserverListThreadSafe<ApplicationStatusListenerImpl>,
LeakyLazyObserverListTraits>
g_observers = LAZY_INSTANCE_INITIALIZER;
class ApplicationStatusListenerImpl : public ApplicationStatusListener {
public:
ApplicationStatusListenerImpl(
const ApplicationStateChangeCallback& callback) {
SetCallback(callback);
g_observers.Get().AddObserver(this);
Java_ApplicationStatus_registerThreadSafeNativeApplicationStateListener(
AttachCurrentThread());
}
~ApplicationStatusListenerImpl() override {
g_observers.Get().RemoveObserver(this);
}
void SetCallback(const ApplicationStateChangeCallback& callback) override {
DCHECK(!callback_);
DCHECK(callback);
callback_ = callback;
}
void Notify(ApplicationState state) override {
if (callback_)
callback_.Run(state);
}
private:
ApplicationStateChangeCallback callback_;
};
} // namespace
ApplicationStatusListener::ApplicationStatusListener() = default;
ApplicationStatusListener::~ApplicationStatusListener() = default;
// static
std::unique_ptr<ApplicationStatusListener> ApplicationStatusListener::New(
const ApplicationStateChangeCallback& callback) {
return std::make_unique<ApplicationStatusListenerImpl>(callback);
}
// static
void ApplicationStatusListener::NotifyApplicationStateChange(
ApplicationState state) {
TRACE_APPLICATION_STATE(state);
switch (state) {
case APPLICATION_STATE_UNKNOWN:
case APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES:
break;
case APPLICATION_STATE_HAS_RUNNING_ACTIVITIES:
RecordAction(UserMetricsAction("Android.LifeCycle.HasRunningActivities"));
break;
case APPLICATION_STATE_HAS_PAUSED_ACTIVITIES:
RecordAction(UserMetricsAction("Android.LifeCycle.HasPausedActivities"));
break;
case APPLICATION_STATE_HAS_STOPPED_ACTIVITIES:
RecordAction(UserMetricsAction("Android.LifeCycle.HasStoppedActivities"));
break;
}
g_observers.Get().Notify(FROM_HERE, &ApplicationStatusListenerImpl::Notify,
state);
}
// static
ApplicationState ApplicationStatusListener::GetState() {
return static_cast<ApplicationState>(
Java_ApplicationStatus_getStateForApplication(AttachCurrentThread()));
}
static void JNI_ApplicationStatus_OnApplicationStateChange(
JNIEnv* env,
jint new_state) {
ApplicationState application_state = static_cast<ApplicationState>(new_state);
ApplicationStatusListener::NotifyApplicationStateChange(application_state);
}
// static
bool ApplicationStatusListener::HasVisibleActivities() {
return Java_ApplicationStatus_hasVisibleActivities(AttachCurrentThread());
}
} // namespace android
} // namespace base