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/contextualsearch/contextual_search_manager.h"
9 #include "base/android/jni_string.h"
10 #include "base/callback.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/time/time.h"
13 #include "chrome/browser/android/contextualsearch/contextual_search_delegate.h"
14 #include "chrome/browser/android/tab_android.h"
15 #include "chrome/browser/history/history_service_factory.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/search/contextual_search_promo_source_android.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/browser/ui/android/window_android_helper.h"
20 #include "components/history/core/browser/history_service.h"
21 #include "components/navigation_interception/intercept_navigation_delegate.h"
22 #include "components/variations/variations_associated_data.h"
23 #include "components/web_contents_delegate_android/web_contents_delegate_android.h"
24 #include "content/public/browser/android/content_view_core.h"
25 #include "content/public/browser/web_contents.h"
26 #include "jni/ContextualSearchManager_jni.h"
27 #include "net/url_request/url_fetcher_impl.h"
29 using content::ContentViewCore
;
33 // Field trial related constants.
34 const char kContextualSearchFieldTrialName
[] = "ContextualSearch";
35 const char kContextualSearchHidePromoHeaderParam
[] = "hide_promo_header";
36 const char kContextualSearchEnabledValue
[] = "enabled";
38 const int kHistoryDeletionWindowSeconds
= 2;
40 // Because we need a callback, this needs to exist.
41 void OnHistoryDeletionDone() {
46 // This class manages the native behavior of the Contextual Search feature.
47 // Instances of this class are owned by the Java ContextualSearchManager.
48 // Most of the work is actually done in an associated delegate to this class:
49 // the ContextualSearchDelegate.
50 ContextualSearchManager::ContextualSearchManager(JNIEnv
* env
, jobject obj
) {
51 java_manager_
.Reset(env
, obj
);
52 Java_ContextualSearchManager_setNativeManager(
53 env
, obj
, reinterpret_cast<intptr_t>(this));
54 Profile
* profile
= ProfileManager::GetActiveUserProfile();
55 delegate_
.reset(new ContextualSearchDelegate(
56 profile
->GetRequestContext(),
57 TemplateURLServiceFactory::GetForProfile(profile
),
58 base::Bind(&ContextualSearchManager::OnSearchTermResolutionResponse
,
59 base::Unretained(this)),
60 base::Bind(&ContextualSearchManager::OnSurroundingTextAvailable
,
61 base::Unretained(this)),
62 base::Bind(&ContextualSearchManager::OnIcingSelectionAvailable
,
63 base::Unretained(this))));
64 content::URLDataSource::Add(ProfileManager::GetActiveUserProfile(),
65 new ContextualSearchPromoSourceAndroid());
68 ContextualSearchManager::~ContextualSearchManager() {
69 JNIEnv
* env
= base::android::AttachCurrentThread();
70 Java_ContextualSearchManager_clearNativeManager(env
, java_manager_
.obj());
73 void ContextualSearchManager::Destroy(JNIEnv
* env
, jobject obj
) { delete this; }
75 void ContextualSearchManager::StartSearchTermResolutionRequest(
79 jboolean j_use_resolved_search_term
,
80 jobject j_base_content_view_core
) {
81 ContentViewCore
* base_content_view_core
=
82 ContentViewCore::GetNativeContentViewCore(env
, j_base_content_view_core
);
83 DCHECK(base_content_view_core
);
84 std::string
selection(
85 base::android::ConvertJavaStringToUTF8(env
, j_selection
));
86 bool use_resolved_search_term
= j_use_resolved_search_term
;
87 // Calls back to OnSearchTermResolutionResponse.
88 delegate_
->StartSearchTermResolutionRequest(
89 selection
, use_resolved_search_term
, base_content_view_core
);
92 void ContextualSearchManager::GatherSurroundingText(
96 jboolean j_use_resolved_search_term
,
97 jobject j_base_content_view_core
) {
98 ContentViewCore
* base_content_view_core
=
99 ContentViewCore::GetNativeContentViewCore(env
, j_base_content_view_core
);
100 DCHECK(base_content_view_core
);
101 std::string
selection(
102 base::android::ConvertJavaStringToUTF8(env
, j_selection
));
103 bool use_resolved_search_term
= j_use_resolved_search_term
;
104 delegate_
->GatherAndSaveSurroundingText(
105 selection
, use_resolved_search_term
, base_content_view_core
);
108 void ContextualSearchManager::ContinueSearchTermResolutionRequest(JNIEnv
* env
,
110 delegate_
->ContinueSearchTermResolutionRequest();
113 void ContextualSearchManager::OnSearchTermResolutionResponse(
116 const std::string
& search_term
,
117 const std::string
& display_text
,
118 const std::string
& alternate_term
,
119 bool prevent_preload
) {
120 // Notify the Java UX of the result.
121 JNIEnv
* env
= base::android::AttachCurrentThread();
122 base::android::ScopedJavaLocalRef
<jstring
> j_search_term
=
123 base::android::ConvertUTF8ToJavaString(env
, search_term
.c_str());
124 base::android::ScopedJavaLocalRef
<jstring
> j_display_text
=
125 base::android::ConvertUTF8ToJavaString(env
, display_text
.c_str());
126 base::android::ScopedJavaLocalRef
<jstring
> j_alternate_term
=
127 base::android::ConvertUTF8ToJavaString(env
, alternate_term
.c_str());
128 Java_ContextualSearchManager_onSearchTermResolutionResponse(
134 j_display_text
.obj(),
135 j_alternate_term
.obj(),
139 void ContextualSearchManager::OnSurroundingTextAvailable(
140 const std::string
& before_text
,
141 const std::string
& after_text
) {
142 JNIEnv
* env
= base::android::AttachCurrentThread();
143 base::android::ScopedJavaLocalRef
<jstring
> j_before_text
=
144 base::android::ConvertUTF8ToJavaString(env
, before_text
.c_str());
145 base::android::ScopedJavaLocalRef
<jstring
> j_after_text
=
146 base::android::ConvertUTF8ToJavaString(env
, after_text
.c_str());
147 Java_ContextualSearchManager_onSurroundingTextAvailable(
154 void ContextualSearchManager::OnIcingSelectionAvailable(
155 const std::string
& encoding
,
156 const base::string16
& surrounding_text
,
159 JNIEnv
* env
= base::android::AttachCurrentThread();
160 base::android::ScopedJavaLocalRef
<jstring
> j_encoding
=
161 base::android::ConvertUTF8ToJavaString(env
, encoding
.c_str());
162 base::android::ScopedJavaLocalRef
<jstring
> j_surrounding_text
=
163 base::android::ConvertUTF16ToJavaString(env
, surrounding_text
.c_str());
164 Java_ContextualSearchManager_onIcingSelectionAvailable(
165 env
, java_manager_
.obj(), j_encoding
.obj(), j_surrounding_text
.obj(),
166 start_offset
, end_offset
);
169 void ContextualSearchManager::RemoveLastSearchVisit(
173 jlong search_start_time_ms
) {
174 // The deletion window is from the time a search URL was put in history, up
175 // to a short amount of time later.
176 base::Time begin_time
= base::Time::FromJsTime(search_start_time_ms
);
177 base::Time end_time
= begin_time
+
178 base::TimeDelta::FromSeconds(kHistoryDeletionWindowSeconds
);
180 history::HistoryService
* service
= HistoryServiceFactory::GetForProfile(
181 ProfileManager::GetActiveUserProfile(),
182 ServiceAccessType::EXPLICIT_ACCESS
);
184 // NOTE(mathp): We are only removing |search_url| from the local history
185 // because search results that are not promoted to a Tab do not make it to
186 // the web history, only local.
187 std::set
<GURL
> restrict_set
;
189 GURL(base::android::ConvertJavaStringToUTF8(env
, search_url
)));
190 service
->ExpireHistoryBetween(
194 base::Bind(&OnHistoryDeletionDone
),
195 &history_task_tracker_
);
199 void ContextualSearchManager::SetWebContents(JNIEnv
* env
,
201 jobject jcontent_view_core
,
202 jobject jweb_contents_delegate
) {
203 content::ContentViewCore
* content_view_core
=
204 content::ContentViewCore::GetNativeContentViewCore(env
,
206 DCHECK(content_view_core
);
207 DCHECK(content_view_core
->GetWebContents());
209 // NOTE(pedrosimonetti): Takes ownership of the WebContents associated
210 // with the ContentViewCore. This is to make sure that the WebContens
211 // and the Compositor are in the same process.
212 // TODO(pedrosimonetti): Confirm with dtrainor@ if the comment above
214 web_contents_
.reset(content_view_core
->GetWebContents());
215 // TODO(pedrosimonetti): confirm if we need this after promoting it
217 TabAndroid::AttachTabHelpers(web_contents_
.get());
218 WindowAndroidHelper::FromWebContents(web_contents_
.get())
219 ->SetWindowAndroid(content_view_core
->GetWindowAndroid());
220 web_contents_delegate_
.reset(
221 new web_contents_delegate_android::WebContentsDelegateAndroid(
222 env
, jweb_contents_delegate
));
223 web_contents_
->SetDelegate(web_contents_delegate_
.get());
226 void ContextualSearchManager::DestroyWebContents(JNIEnv
* env
, jobject jobj
) {
227 DCHECK(web_contents_
.get());
228 web_contents_
.reset();
229 // |web_contents_delegate_| may already be NULL at this point.
230 web_contents_delegate_
.reset();
233 void ContextualSearchManager::ReleaseWebContents(JNIEnv
* env
, jobject jboj
) {
234 DCHECK(web_contents_
.get());
235 web_contents_delegate_
.reset();
236 ignore_result(web_contents_
.release());
239 void ContextualSearchManager::DestroyWebContentsFromContentViewCore(
242 jobject jcontent_view_core
) {
243 content::ContentViewCore
* content_view_core
=
244 content::ContentViewCore::GetNativeContentViewCore(env
,
246 DCHECK(content_view_core
);
247 DCHECK(content_view_core
->GetWebContents());
249 delete content_view_core
->GetWebContents();
252 bool ContextualSearchManager::ShouldHidePromoHeader(JNIEnv
* env
,
254 return variations::GetVariationParamValue(
255 kContextualSearchFieldTrialName
,
256 kContextualSearchHidePromoHeaderParam
) ==
257 kContextualSearchEnabledValue
;
260 void ContextualSearchManager::SetInterceptNavigationDelegate(
264 jobject jweb_contents
) {
265 content::WebContents
* web_contents
=
266 content::WebContents::FromJavaWebContents(jweb_contents
);
267 DCHECK(web_contents
);
268 navigation_interception::InterceptNavigationDelegate::Associate(
270 make_scoped_ptr(new navigation_interception::InterceptNavigationDelegate(
274 bool RegisterContextualSearchManager(JNIEnv
* env
) {
275 return RegisterNativesImpl(env
);
278 jlong
Init(JNIEnv
* env
, jobject obj
) {
279 ContextualSearchManager
* manager
= new ContextualSearchManager(env
, obj
);
280 return reinterpret_cast<intptr_t>(manager
);