1 // Copyright 2015 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.
5 #include "chrome/browser/android/feedback/connectivity_checker.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/android/scoped_java_ref.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/time/time.h"
12 #include "base/timer/timer.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/profiles/profile_android.h"
15 #include "jni/ConnectivityChecker_jni.h"
16 #include "net/base/load_flags.h"
17 #include "net/http/http_status_code.h"
18 #include "net/url_request/url_fetcher.h"
19 #include "net/url_request/url_fetcher_delegate.h"
20 #include "net/url_request/url_request_context_getter.h"
21 #include "net/url_request/url_request_status.h"
28 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.feedback
29 // GENERATED_JAVA_PREFIX_TO_STRIP: CONNECTIVITY_CHECK_RESULT_
30 enum ConnectivityCheckResult
{
31 CONNECTIVITY_CHECK_RESULT_UNKNOWN
= 0,
32 CONNECTIVITY_CHECK_RESULT_CONNECTED
= 1,
33 CONNECTIVITY_CHECK_RESULT_NOT_CONNECTED
= 2,
34 CONNECTIVITY_CHECK_RESULT_TIMEOUT
= 3,
35 CONNECTIVITY_CHECK_RESULT_ERROR
= 4,
36 CONNECTIVITY_CHECK_RESULT_END
= 5
39 void ExecuteCallback(jobject callback
, ConnectivityCheckResult result
) {
40 CHECK(result
>= CONNECTIVITY_CHECK_RESULT_UNKNOWN
);
41 CHECK(result
< CONNECTIVITY_CHECK_RESULT_END
);
42 Java_ConnectivityChecker_executeCallback(base::android::AttachCurrentThread(),
46 void ExecuteCallbackFromRef(
47 base::android::ScopedJavaGlobalRef
<jobject
>* callback
,
48 ConnectivityCheckResult result
) {
49 ExecuteCallback(callback
->obj(), result
);
52 void PostCallback(JNIEnv
* env
,
54 ConnectivityCheckResult result
) {
55 base::MessageLoop::current()->PostTask(
57 base::Bind(&ExecuteCallbackFromRef
,
58 base::Owned(new base::android::ScopedJavaGlobalRef
<jobject
>(
63 // A utility class for checking if the device is currently connected to the
65 class ConnectivityChecker
: public net::URLFetcherDelegate
{
67 ConnectivityChecker(Profile
* profile
,
69 const base::TimeDelta
& timeout
,
70 const base::android::JavaRef
<jobject
>& java_callback
);
72 // Kicks off the asynchronous connectivity check. When the request has
73 // completed, |this| is deleted.
74 void StartAsyncCheck();
76 // net::URLFetcherDelegate implementation:
77 void OnURLFetchComplete(const net::URLFetcher
* source
) override
;
79 // Cancels the URLFetcher, and triggers the callback with a negative result
80 // and the timeout flag set.
84 // The context in which the connectivity check is performed.
85 net::URLRequestContextGetter
* request_context_
;
87 // The URL to connect to.
90 // How long to wait for a response before giving up.
91 const base::TimeDelta timeout_
;
93 // Holds the Java object which will get the callback with the result.
94 base::android::ScopedJavaGlobalRef
<jobject
> java_callback_
;
96 // The URLFetcher that executes the connectivity check.
97 scoped_ptr
<net::URLFetcher
> url_fetcher_
;
99 // Whether |this| is already being destroyed, at which point the callback
100 // has already happened, and no further action should be taken.
101 bool is_being_destroyed_
;
103 scoped_ptr
<base::OneShotTimer
<ConnectivityChecker
>> expiration_timer_
;
106 void ConnectivityChecker::OnURLFetchComplete(const net::URLFetcher
* source
) {
107 if (is_being_destroyed_
)
109 is_being_destroyed_
= true;
111 DCHECK_EQ(url_fetcher_
.get(), source
);
112 net::URLRequestStatus status
= source
->GetStatus();
113 int response_code
= source
->GetResponseCode();
115 bool connected
= status
.is_success() && response_code
== net::HTTP_NO_CONTENT
;
117 ExecuteCallback(java_callback_
.obj(), CONNECTIVITY_CHECK_RESULT_CONNECTED
);
119 ExecuteCallback(java_callback_
.obj(),
120 CONNECTIVITY_CHECK_RESULT_NOT_CONNECTED
);
123 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
126 ConnectivityChecker::ConnectivityChecker(
129 const base::TimeDelta
& timeout
,
130 const base::android::JavaRef
<jobject
>& java_callback
)
131 : request_context_(profile
->GetRequestContext()),
134 java_callback_(java_callback
),
135 is_being_destroyed_(false) {
138 void ConnectivityChecker::StartAsyncCheck() {
140 net::URLFetcher::Create(url_
, net::URLFetcher::GET
, this).Pass();
141 url_fetcher_
->SetRequestContext(request_context_
);
142 url_fetcher_
->SetStopOnRedirect(true);
143 url_fetcher_
->SetAutomaticallyRetryOn5xx(false);
144 url_fetcher_
->SetAutomaticallyRetryOnNetworkChanges(0);
145 url_fetcher_
->SetLoadFlags(net::LOAD_BYPASS_CACHE
| net::LOAD_DISABLE_CACHE
|
146 net::LOAD_DO_NOT_SAVE_COOKIES
|
147 net::LOAD_DO_NOT_SEND_COOKIES
|
148 net::LOAD_DO_NOT_SEND_AUTH_DATA
);
149 url_fetcher_
->Start();
150 expiration_timer_
.reset(new base::OneShotTimer
<ConnectivityChecker
>());
151 expiration_timer_
->Start(FROM_HERE
, timeout_
, this,
152 &ConnectivityChecker::OnTimeout
);
155 void ConnectivityChecker::OnTimeout() {
156 if (is_being_destroyed_
)
158 is_being_destroyed_
= true;
159 url_fetcher_
.reset();
160 ExecuteCallback(java_callback_
.obj(), CONNECTIVITY_CHECK_RESULT_TIMEOUT
);
161 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
166 void CheckConnectivity(JNIEnv
* env
,
167 const JavaParamRef
<jclass
>& clazz
,
168 const JavaParamRef
<jobject
>& j_profile
,
169 const JavaParamRef
<jstring
>& j_url
,
171 const JavaParamRef
<jobject
>& j_callback
) {
172 Profile
* profile
= ProfileAndroid::FromProfileAndroid(j_profile
);
174 PostCallback(env
, j_callback
, CONNECTIVITY_CHECK_RESULT_ERROR
);
177 GURL
url(base::android::ConvertJavaStringToUTF8(env
, j_url
));
178 if (!url
.is_valid()) {
179 PostCallback(env
, j_callback
, CONNECTIVITY_CHECK_RESULT_ERROR
);
183 // This object will be deleted when the connectivity check has completed.
184 ConnectivityChecker
* connectivity_checker
= new ConnectivityChecker(
185 profile
, url
, base::TimeDelta::FromMilliseconds(j_timeout_ms
),
186 base::android::ScopedJavaLocalRef
<jobject
>(env
, j_callback
));
187 connectivity_checker
->StartAsyncCheck();
190 jboolean
IsUrlValid(JNIEnv
* env
,
191 const JavaParamRef
<jclass
>& clazz
,
192 const JavaParamRef
<jstring
>& j_url
) {
193 GURL
url(base::android::ConvertJavaStringToUTF8(env
, j_url
));
194 return url
.is_valid();
197 bool RegisterConnectivityChecker(JNIEnv
* env
) {
198 return RegisterNativesImpl(env
);
201 } // namespace android
202 } // namespace chrome