1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "modules/netinfo/NetworkInformation.h"
7
8 #include "core/dom/ExecutionContext.h"
9 #include "core/events/Event.h"
10 #include "core/page/NetworkStateNotifier.h"
11 #include "modules/EventTargetModules.h"
12 #include "wtf/text/WTFString.h"
13
14 namespace {
15
connectionTypeToString(blink::WebConnectionType type)16 String connectionTypeToString(blink::WebConnectionType type)
17 {
18 switch (type) {
19 case blink::ConnectionTypeCellular:
20 return "cellular";
21 case blink::ConnectionTypeBluetooth:
22 return "bluetooth";
23 case blink::ConnectionTypeEthernet:
24 return "ethernet";
25 case blink::ConnectionTypeWifi:
26 return "wifi";
27 case blink::ConnectionTypeOther:
28 return "other";
29 case blink::ConnectionTypeNone:
30 return "none";
31 case blink::ConnectionTypeUnknown:
32 return "unknown";
33 }
34 ASSERT_NOT_REACHED();
35 return "none";
36 }
37
38 } // namespace
39
40 namespace blink {
41
create(ExecutionContext * context)42 NetworkInformation* NetworkInformation::create(ExecutionContext* context)
43 {
44 NetworkInformation* connection = adoptRefCountedGarbageCollectedWillBeNoop(new NetworkInformation(context));
45 connection->suspendIfNeeded();
46 return connection;
47 }
48
~NetworkInformation()49 NetworkInformation::~NetworkInformation()
50 {
51 ASSERT(!m_observing);
52 }
53
type() const54 String NetworkInformation::type() const
55 {
56 // m_type is only updated when listening for events, so ask networkStateNotifier
57 // if not listening (crbug.com/379841).
58 if (!m_observing)
59 return connectionTypeToString(networkStateNotifier().connectionType());
60
61 // If observing, return m_type which changes when the event fires, per spec.
62 return connectionTypeToString(m_type);
63 }
64
connectionTypeChange(WebConnectionType type)65 void NetworkInformation::connectionTypeChange(WebConnectionType type)
66 {
67 ASSERT(executionContext()->isContextThread());
68
69 // This can happen if the observer removes and then adds itself again
70 // during notification.
71 if (m_type == type)
72 return;
73
74 m_type = type;
75 dispatchEvent(Event::create(EventTypeNames::typechange));
76 }
77
interfaceName() const78 const AtomicString& NetworkInformation::interfaceName() const
79 {
80 return EventTargetNames::NetworkInformation;
81 }
82
executionContext() const83 ExecutionContext* NetworkInformation::executionContext() const
84 {
85 return ActiveDOMObject::executionContext();
86 }
87
addEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener,bool useCapture)88 bool NetworkInformation::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
89 {
90 if (!EventTargetWithInlineData::addEventListener(eventType, listener, useCapture))
91 return false;
92 startObserving();
93 return true;
94 }
95
removeEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener,bool useCapture)96 bool NetworkInformation::removeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
97 {
98 if (!EventTargetWithInlineData::removeEventListener(eventType, listener, useCapture))
99 return false;
100 if (!hasEventListeners())
101 stopObserving();
102 return true;
103 }
104
removeAllEventListeners()105 void NetworkInformation::removeAllEventListeners()
106 {
107 EventTargetWithInlineData::removeAllEventListeners();
108 ASSERT(!hasEventListeners());
109 stopObserving();
110 }
111
hasPendingActivity() const112 bool NetworkInformation::hasPendingActivity() const
113 {
114 ASSERT(m_contextStopped || m_observing == hasEventListeners());
115
116 // Prevent collection of this object when there are active listeners.
117 return m_observing;
118 }
119
stop()120 void NetworkInformation::stop()
121 {
122 m_contextStopped = true;
123 stopObserving();
124 }
125
startObserving()126 void NetworkInformation::startObserving()
127 {
128 if (!m_observing && !m_contextStopped) {
129 m_type = networkStateNotifier().connectionType();
130 networkStateNotifier().addObserver(this, executionContext());
131 m_observing = true;
132 }
133 }
134
stopObserving()135 void NetworkInformation::stopObserving()
136 {
137 if (m_observing) {
138 networkStateNotifier().removeObserver(this, executionContext());
139 m_observing = false;
140 }
141 }
142
NetworkInformation(ExecutionContext * context)143 NetworkInformation::NetworkInformation(ExecutionContext* context)
144 : ActiveDOMObject(context)
145 , m_type(networkStateNotifier().connectionType())
146 , m_observing(false)
147 , m_contextStopped(false)
148 {
149 }
150
151 } // namespace blink
152