PageRenderTime 29ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java

http://github.com/chromium/chromium
Java | 294 lines | 147 code | 31 blank | 116 comment | 17 complexity | c59f486f52a908af6e1525c1faf7455c MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
  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.
  4. package org.chromium.chrome.browser.contextualsearch;
  5. import android.net.Uri;
  6. import android.text.TextUtils;
  7. import androidx.annotation.Nullable;
  8. import androidx.annotation.VisibleForTesting;
  9. import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
  10. import org.chromium.components.embedder_support.util.UrlUtilitiesJni;
  11. import java.net.MalformedURLException;
  12. import java.net.URL;
  13. /**
  14. * Bundles a Search Request URL with a low-priority version of the URL, helps manage the
  15. * fall-back when the low-priority version fails, and tracks which one is in use.
  16. */
  17. class ContextualSearchRequest {
  18. private final boolean mWasPrefetch;
  19. private Uri mLowPriorityUri;
  20. private Uri mNormalPriorityUri;
  21. private boolean mIsLowPriority;
  22. private boolean mHasFailedLowPriorityLoad;
  23. private boolean mIsTranslationForced;
  24. private boolean mIsFullSearchUrlProvided;
  25. private static final String GWS_NORMAL_PRIORITY_SEARCH_PATH = "search";
  26. private static final String GWS_LOW_PRIORITY_SEARCH_PATH = "s";
  27. private static final String GWS_SEARCH_NO_SUGGESTIONS_PARAM = "sns";
  28. private static final String GWS_SEARCH_NO_SUGGESTIONS_PARAM_VALUE = "1";
  29. private static final String GWS_QUERY_PARAM = "q";
  30. private static final String CTXS_PARAM_PATTERN = "(ctxs=[^&]+)";
  31. private static final String CTXR_PARAM = "ctxr";
  32. private static final String PF_PARAM = "(\\&pf=\\w)";
  33. private static final String CTXS_TWO_REQUEST_PROTOCOL = "2";
  34. private static final String CTXSL_TRANS_PARAM = "ctxsl_trans";
  35. private static final String CTXSL_TRANS_PARAM_VALUE = "1";
  36. @VisibleForTesting static final String TLITE_SOURCE_LANGUAGE_PARAM = "tlitesl";
  37. private static final String TLITE_TARGET_LANGUAGE_PARAM = "tlitetl";
  38. private static final String TLITE_QUERY_PARAM = "tlitetxt";
  39. private static final String KP_TRIGGERING_MID_PARAM = "kgmid";
  40. /**
  41. * Creates a search request for the given search term without any alternate term and
  42. * for normal-priority loading capability only.
  43. * @param searchTerm The resolved search term.
  44. */
  45. ContextualSearchRequest(String searchTerm) {
  46. this(searchTerm, false);
  47. }
  48. /**
  49. * Creates a search request for the given search term without any alternate term and
  50. * for low-priority loading capability if specified in the second parameter.
  51. * @param searchTerm The resolved search term.
  52. * @param isLowPriorityEnabled Whether the request can be made at a low priority.
  53. */
  54. ContextualSearchRequest(String searchTerm, boolean isLowPriorityEnabled) {
  55. this(searchTerm, null, null, isLowPriorityEnabled, null, null);
  56. }
  57. /**
  58. * Creates a search request for the given search term, unless the full search URL is provided
  59. * in the {@code searchUrlFull}. When the full URL is not provided the request also uses the
  60. * given alternate term, mid, and low-priority loading capability. <p>
  61. * If the {@code searchUrlPreload} is provided then the {@code searchUrlFull} should also be
  62. * provided.
  63. * @param searchTerm The resolved search term.
  64. * @param alternateTerm The alternate search term.
  65. * @param mid The MID for an entity to use to trigger a Knowledge Panel, or an empty string.
  66. * A MID is a unique identifier for an entity in the Search Knowledge Graph.
  67. * @param isLowPriorityEnabled Whether the request can be made at a low priority.
  68. * @param searchUrlFull The URL for the full search to present in the overlay, or empty.
  69. * @param searchUrlPreload The URL for the search to preload into the overlay, or empty.
  70. */
  71. ContextualSearchRequest(String searchTerm, @Nullable String alternateTerm, @Nullable String mid,
  72. boolean isLowPriorityEnabled, @Nullable String searchUrlFull,
  73. @Nullable String searchUrlPreload) {
  74. mWasPrefetch = isLowPriorityEnabled;
  75. mIsFullSearchUrlProvided = isGoogleUrl(searchUrlFull);
  76. mNormalPriorityUri = mIsFullSearchUrlProvided
  77. ? Uri.parse(searchUrlFull)
  78. : getUriTemplate(searchTerm, alternateTerm, mid, false);
  79. if (isLowPriorityEnabled) {
  80. if (isGoogleUrl(searchUrlPreload)) {
  81. mLowPriorityUri = Uri.parse(searchUrlPreload);
  82. } else {
  83. Uri baseLowPriorityUri = getUriTemplate(searchTerm, alternateTerm, mid, true);
  84. mLowPriorityUri = makeLowPriorityUri(baseLowPriorityUri);
  85. }
  86. } else {
  87. mLowPriorityUri = null;
  88. }
  89. mIsLowPriority = isLowPriorityEnabled;
  90. }
  91. /**
  92. * Sets an indicator that the normal-priority URL should be used for this search request.
  93. */
  94. void setNormalPriority() {
  95. mIsLowPriority = false;
  96. }
  97. /**
  98. * @return whether the low priority URL is being used.
  99. */
  100. boolean isUsingLowPriority() {
  101. return mIsLowPriority;
  102. }
  103. /**
  104. * @return whether this request started as a prefetch request.
  105. */
  106. boolean wasPrefetch() {
  107. return mWasPrefetch;
  108. }
  109. /**
  110. * Sets that this search request has failed.
  111. */
  112. void setHasFailed() {
  113. mHasFailedLowPriorityLoad = true;
  114. }
  115. /**
  116. * @return whether the load has failed for this search request or not.
  117. */
  118. boolean getHasFailed() {
  119. return mHasFailedLowPriorityLoad;
  120. }
  121. /**
  122. * Gets the search URL for this request.
  123. * @return either the low-priority or normal-priority URL for this search request.
  124. */
  125. String getSearchUrl() {
  126. return mIsLowPriority && mLowPriorityUri != null ? mLowPriorityUri.toString()
  127. : mNormalPriorityUri.toString();
  128. }
  129. /**
  130. * Returns whether the given URL is the current Contextual Search URL.
  131. * @param url The given URL.
  132. * @return Whether it is the current Contextual Search URL.
  133. */
  134. boolean isContextualSearchUrl(String url) {
  135. return url.equals(getSearchUrl());
  136. }
  137. /**
  138. * Returns the formatted Search URL, replacing the ctxs param with the ctxr param, so that
  139. * the SearchBox will becomes visible, while preserving the Answers Mode.
  140. *
  141. * @return The formatted Search URL.
  142. */
  143. String getSearchUrlForPromotion() {
  144. setNormalPriority();
  145. String searchUrl = getSearchUrl();
  146. URL url;
  147. try {
  148. url = new URL(
  149. searchUrl.replaceAll(CTXS_PARAM_PATTERN, CTXR_PARAM).replaceAll(PF_PARAM, ""));
  150. } catch (MalformedURLException e) {
  151. url = null;
  152. }
  153. return url != null ? url.toString() : null;
  154. }
  155. /**
  156. * Adds translation parameters.
  157. * @param sourceLanguage The language of the original search term.
  158. * @param targetLanguage The language the that the user prefers.
  159. */
  160. void forceTranslation(String sourceLanguage, String targetLanguage) {
  161. mIsTranslationForced = true;
  162. // If the server is providing a full URL then we shouldn't alter it.
  163. if (mIsFullSearchUrlProvided) return;
  164. if (mLowPriorityUri != null) {
  165. mLowPriorityUri = makeTranslateUri(mLowPriorityUri, sourceLanguage, targetLanguage);
  166. }
  167. mNormalPriorityUri = makeTranslateUri(mNormalPriorityUri, sourceLanguage, targetLanguage);
  168. }
  169. /**
  170. * Adds translation parameters that will trigger auto-detection of the source language.
  171. * @param targetLanguage The language the that the user prefers.
  172. */
  173. void forceAutoDetectTranslation(String targetLanguage) {
  174. // Use the empty string for the source language in order to trigger auto-detect.
  175. forceTranslation("", targetLanguage);
  176. }
  177. /**
  178. * @return Whether translation was forced for this request (for testing only).
  179. */
  180. @VisibleForTesting
  181. boolean isTranslationForced() {
  182. return mIsTranslationForced;
  183. }
  184. /**
  185. * Uses TemplateUrlService to generate the url for the given query
  186. * {@link String} for {@code query} with the contextual search version param set.
  187. * @param query The search term to use as the main query in the returned search url.
  188. * @param alternateTerm The alternate search term to use as an alternate suggestion.
  189. * @param mid The MID for an entity to use to trigger a Knowledge Panel, or an empty string.
  190. * A MID is a unique identifier for an entity in the Search Knowledge Graph.
  191. * @param shouldPrefetch Whether the returned url should include a prefetch parameter.
  192. * @return A {@link Uri} that contains the url of the default search engine with
  193. * {@code query} and {@code alternateTerm} inserted as parameters and contextual
  194. * search and prefetch parameters conditionally set.
  195. */
  196. protected Uri getUriTemplate(String query, @Nullable String alternateTerm, @Nullable String mid,
  197. boolean shouldPrefetch) {
  198. // TODO(https://crbug.com/783819): Avoid parsing the GURL as a Uri, and update
  199. // makeKPTriggeringUri to operate on GURLs.
  200. Uri uri = Uri.parse(TemplateUrlServiceFactory.get()
  201. .getUrlForContextualSearchQuery(query, alternateTerm,
  202. shouldPrefetch, CTXS_TWO_REQUEST_PROTOCOL)
  203. .getSpec());
  204. if (!TextUtils.isEmpty(mid)) uri = makeKPTriggeringUri(uri, mid);
  205. return uri;
  206. }
  207. /**
  208. * Judges if the given URL looks like a Google URL.
  209. * @param someUrl A URL to judge.
  210. * @return Whether it's pointing to Google infrastructure or not.
  211. */
  212. @VisibleForTesting
  213. boolean isGoogleUrl(@Nullable String someUrl) {
  214. return !TextUtils.isEmpty(someUrl) && UrlUtilitiesJni.get().isGoogleSubDomainUrl(someUrl);
  215. }
  216. /**
  217. * @return a low-priority {@code Uri} from the given base {@code Uri}.
  218. */
  219. private Uri makeLowPriorityUri(Uri baseUri) {
  220. if (baseUri.getPath() == null
  221. || !baseUri.getPath().contains(GWS_NORMAL_PRIORITY_SEARCH_PATH)) {
  222. return baseUri;
  223. }
  224. return baseUri.buildUpon()
  225. .path(GWS_LOW_PRIORITY_SEARCH_PATH)
  226. .appendQueryParameter(
  227. GWS_SEARCH_NO_SUGGESTIONS_PARAM, GWS_SEARCH_NO_SUGGESTIONS_PARAM_VALUE)
  228. .build();
  229. }
  230. /**
  231. * Makes the given {@code Uri} into a similar Uri that triggers a Translate one-box.
  232. * @param baseUri The base Uri to build off of.
  233. * @param sourceLanguage The language of the original search term, or an empty string to
  234. * auto-detect the source language.
  235. * @param targetLanguage The language that the user prefers, or an empty string to
  236. * use server-side heuristics for the target language.
  237. * @return A {@link Uri} that has additional parameters for Translate appropriately set.
  238. */
  239. private Uri makeTranslateUri(Uri baseUri, String sourceLanguage, String targetLanguage) {
  240. Uri.Builder builder = baseUri.buildUpon();
  241. builder.appendQueryParameter(CTXSL_TRANS_PARAM, CTXSL_TRANS_PARAM_VALUE);
  242. if (!sourceLanguage.isEmpty()) {
  243. builder.appendQueryParameter(TLITE_SOURCE_LANGUAGE_PARAM, sourceLanguage);
  244. }
  245. if (!targetLanguage.isEmpty()) {
  246. builder.appendQueryParameter(TLITE_TARGET_LANGUAGE_PARAM, targetLanguage);
  247. }
  248. builder.appendQueryParameter(TLITE_QUERY_PARAM, baseUri.getQueryParameter(GWS_QUERY_PARAM));
  249. return builder.build();
  250. }
  251. /**
  252. * Converts a URI to a URI that will trigger a Knowledge Panel for the given entity.
  253. * @param baseUri The base URI to convert.
  254. * @param mid The un-encoded MID (unique identifier) for an entity to use to trigger a Knowledge
  255. * Panel.
  256. * @return The converted URI.
  257. */
  258. private Uri makeKPTriggeringUri(Uri baseUri, String mid) {
  259. // Need to add a param like &kgmid=/m/0cqt90
  260. // Note that the mid must not be escaped - appendQueryParameter will take care of that.
  261. return baseUri.buildUpon().appendQueryParameter(KP_TRIGGERING_MID_PARAM, mid).build();
  262. }
  263. }