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_engines/template_url_service_factory.h"
18 #include "chrome/browser/ui/android/window_android_helper.h"
19 #include "components/history/core/browser/history_service.h"
20 #include "components/navigation_interception/intercept_navigation_delegate.h"
21 #include "components/variations/variations_associated_data.h"
22 #include "components/web_contents_delegate_android/web_contents_delegate_android.h"
23 #include "content/public/browser/android/content_view_core.h"
24 #include "content/public/browser/web_contents.h"
25 #include "jni/ContextualSearchManager_jni.h"
26 #include "net/url_request/url_fetcher_impl.h"
28 using content::ContentViewCore
;
32 const int kHistoryDeletionWindowSeconds
= 2;
34 // Because we need a callback, this needs to exist.
35 void OnHistoryDeletionDone() {
40 // This class manages the native behavior of the Contextual Search feature.
41 // Instances of this class are owned by the Java ContextualSearchManager.
42 // Most of the work is actually done in an associated delegate to this class:
43 // the ContextualSearchDelegate.
44 ContextualSearchManager::ContextualSearchManager(JNIEnv
* env
, jobject obj
) {
45 java_manager_
.Reset(env
, obj
);
46 Java_ContextualSearchManager_setNativeManager(
47 env
, obj
, reinterpret_cast<intptr_t>(this));
48 Profile
* profile
= ProfileManager::GetActiveUserProfile();
49 delegate_
.reset(new ContextualSearchDelegate(
50 profile
->GetRequestContext(),
51 TemplateURLServiceFactory::GetForProfile(profile
),
52 base::Bind(&ContextualSearchManager::OnSearchTermResolutionResponse
,
53 base::Unretained(this)),
54 base::Bind(&ContextualSearchManager::OnSurroundingTextAvailable
,
55 base::Unretained(this)),
56 base::Bind(&ContextualSearchManager::OnIcingSelectionAvailable
,
57 base::Unretained(this))));
60 ContextualSearchManager::~ContextualSearchManager() {
61 JNIEnv
* env
= base::android::AttachCurrentThread();
62 Java_ContextualSearchManager_clearNativeManager(env
, java_manager_
.obj());
65 void ContextualSearchManager::Destroy(JNIEnv
* env
, jobject obj
) { delete this; }
67 void ContextualSearchManager::StartSearchTermResolutionRequest(
71 jboolean j_use_resolved_search_term
,
72 jobject j_base_content_view_core
,
73 jboolean j_may_send_base_page_url
) {
74 ContentViewCore
* base_content_view_core
=
75 ContentViewCore::GetNativeContentViewCore(env
, j_base_content_view_core
);
76 DCHECK(base_content_view_core
);
77 std::string
selection(
78 base::android::ConvertJavaStringToUTF8(env
, j_selection
));
79 bool use_resolved_search_term
= j_use_resolved_search_term
;
80 bool may_send_base_page_url
= j_may_send_base_page_url
;
81 // Calls back to OnSearchTermResolutionResponse.
82 delegate_
->StartSearchTermResolutionRequest(
83 selection
, use_resolved_search_term
, base_content_view_core
,
84 may_send_base_page_url
);
87 void ContextualSearchManager::GatherSurroundingText(
91 jboolean j_use_resolved_search_term
,
92 jobject j_base_content_view_core
,
93 jboolean j_may_send_base_page_url
) {
94 ContentViewCore
* base_content_view_core
=
95 ContentViewCore::GetNativeContentViewCore(env
, j_base_content_view_core
);
96 DCHECK(base_content_view_core
);
97 std::string
selection(
98 base::android::ConvertJavaStringToUTF8(env
, j_selection
));
99 bool use_resolved_search_term
= j_use_resolved_search_term
;
100 bool may_send_base_page_url
= j_may_send_base_page_url
;
101 delegate_
->GatherAndSaveSurroundingText(selection
, use_resolved_search_term
,
102 base_content_view_core
,
103 may_send_base_page_url
);
106 void ContextualSearchManager::OnSearchTermResolutionResponse(
109 const std::string
& search_term
,
110 const std::string
& display_text
,
111 const std::string
& alternate_term
,
112 bool prevent_preload
,
113 int selection_start_adjust
,
114 int selection_end_adjust
) {
115 // Notify the Java UX of the result.
116 JNIEnv
* env
= base::android::AttachCurrentThread();
117 base::android::ScopedJavaLocalRef
<jstring
> j_search_term
=
118 base::android::ConvertUTF8ToJavaString(env
, search_term
.c_str());
119 base::android::ScopedJavaLocalRef
<jstring
> j_display_text
=
120 base::android::ConvertUTF8ToJavaString(env
, display_text
.c_str());
121 base::android::ScopedJavaLocalRef
<jstring
> j_alternate_term
=
122 base::android::ConvertUTF8ToJavaString(env
, alternate_term
.c_str());
123 Java_ContextualSearchManager_onSearchTermResolutionResponse(
124 env
, java_manager_
.obj(), is_invalid
, response_code
, j_search_term
.obj(),
125 j_display_text
.obj(), j_alternate_term
.obj(), prevent_preload
,
126 selection_start_adjust
, selection_end_adjust
);
129 void ContextualSearchManager::OnSurroundingTextAvailable(
130 const std::string
& before_text
,
131 const std::string
& after_text
) {
132 JNIEnv
* env
= base::android::AttachCurrentThread();
133 base::android::ScopedJavaLocalRef
<jstring
> j_before_text
=
134 base::android::ConvertUTF8ToJavaString(env
, before_text
.c_str());
135 base::android::ScopedJavaLocalRef
<jstring
> j_after_text
=
136 base::android::ConvertUTF8ToJavaString(env
, after_text
.c_str());
137 Java_ContextualSearchManager_onSurroundingTextAvailable(
144 void ContextualSearchManager::OnIcingSelectionAvailable(
145 const std::string
& encoding
,
146 const base::string16
& surrounding_text
,
149 JNIEnv
* env
= base::android::AttachCurrentThread();
150 base::android::ScopedJavaLocalRef
<jstring
> j_encoding
=
151 base::android::ConvertUTF8ToJavaString(env
, encoding
.c_str());
152 base::android::ScopedJavaLocalRef
<jstring
> j_surrounding_text
=
153 base::android::ConvertUTF16ToJavaString(env
, surrounding_text
.c_str());
154 Java_ContextualSearchManager_onIcingSelectionAvailable(
155 env
, java_manager_
.obj(), j_encoding
.obj(), j_surrounding_text
.obj(),
156 start_offset
, end_offset
);
159 void ContextualSearchManager::RemoveLastSearchVisit(
163 jlong search_start_time_ms
) {
164 // The deletion window is from the time a search URL was put in history, up
165 // to a short amount of time later.
166 base::Time begin_time
= base::Time::FromJsTime(search_start_time_ms
);
167 base::Time end_time
= begin_time
+
168 base::TimeDelta::FromSeconds(kHistoryDeletionWindowSeconds
);
170 history::HistoryService
* service
= HistoryServiceFactory::GetForProfile(
171 ProfileManager::GetActiveUserProfile(),
172 ServiceAccessType::EXPLICIT_ACCESS
);
174 // NOTE(mathp): We are only removing |search_url| from the local history
175 // because search results that are not promoted to a Tab do not make it to
176 // the web history, only local.
177 std::set
<GURL
> restrict_set
;
179 GURL(base::android::ConvertJavaStringToUTF8(env
, search_url
)));
180 service
->ExpireHistoryBetween(
184 base::Bind(&OnHistoryDeletionDone
),
185 &history_task_tracker_
);
189 void ContextualSearchManager::SetWebContents(JNIEnv
* env
,
191 jobject jcontent_view_core
,
192 jobject jweb_contents_delegate
) {
193 content::ContentViewCore
* content_view_core
=
194 content::ContentViewCore::GetNativeContentViewCore(env
,
196 DCHECK(content_view_core
);
197 DCHECK(content_view_core
->GetWebContents());
199 // NOTE(pedrosimonetti): Takes ownership of the WebContents associated
200 // with the ContentViewCore. This is to make sure that the WebContens
201 // and the Compositor are in the same process.
202 // TODO(pedrosimonetti): Confirm with dtrainor@ if the comment above
204 web_contents_
.reset(content_view_core
->GetWebContents());
205 // TODO(pedrosimonetti): confirm if we need this after promoting it
207 TabAndroid::AttachTabHelpers(web_contents_
.get());
208 WindowAndroidHelper::FromWebContents(web_contents_
.get())
209 ->SetWindowAndroid(content_view_core
->GetWindowAndroid());
210 web_contents_delegate_
.reset(
211 new web_contents_delegate_android::WebContentsDelegateAndroid(
212 env
, jweb_contents_delegate
));
213 web_contents_
->SetDelegate(web_contents_delegate_
.get());
216 void ContextualSearchManager::DestroyWebContents(JNIEnv
* env
, jobject jobj
) {
217 DCHECK(web_contents_
.get());
218 web_contents_
.reset();
219 // |web_contents_delegate_| may already be NULL at this point.
220 web_contents_delegate_
.reset();
223 void ContextualSearchManager::ReleaseWebContents(JNIEnv
* env
, jobject jboj
) {
224 DCHECK(web_contents_
.get());
225 web_contents_delegate_
.reset();
226 ignore_result(web_contents_
.release());
229 void ContextualSearchManager::DestroyWebContentsFromContentViewCore(
232 jobject jcontent_view_core
) {
233 content::ContentViewCore
* content_view_core
=
234 content::ContentViewCore::GetNativeContentViewCore(env
,
236 DCHECK(content_view_core
);
237 DCHECK(content_view_core
->GetWebContents());
239 delete content_view_core
->GetWebContents();
242 void ContextualSearchManager::SetInterceptNavigationDelegate(
246 jobject jweb_contents
) {
247 content::WebContents
* web_contents
=
248 content::WebContents::FromJavaWebContents(jweb_contents
);
249 DCHECK(web_contents
);
250 navigation_interception::InterceptNavigationDelegate::Associate(
252 make_scoped_ptr(new navigation_interception::InterceptNavigationDelegate(
256 bool RegisterContextualSearchManager(JNIEnv
* env
) {
257 return RegisterNativesImpl(env
);
260 jlong
Init(JNIEnv
* env
, jobject obj
) {
261 ContextualSearchManager
* manager
= new ContextualSearchManager(env
, obj
);
262 return reinterpret_cast<intptr_t>(manager
);