1 // Copyright 2019 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 package org.chromium.chrome.browser.contextualsearch; 6 7 import android.text.TextUtils; 8 9 import androidx.annotation.IntDef; 10 11 import java.lang.annotation.Retention; 12 import java.lang.annotation.RetentionPolicy; 13 import java.net.HttpURLConnection; 14 import java.util.ArrayList; 15 import java.util.List; 16 17 /** 18 * Encapsulates the response from the server to a Resolve request (as a single immutable object). 19 */ 20 public class ResolvedSearchTerm { 21 @IntDef({CardTag.CT_NONE, CardTag.CT_OTHER, CardTag.CT_HAS_ENTITY, CardTag.CT_BUSINESS, 22 CardTag.CT_PRODUCT, CardTag.CT_CONTACT, CardTag.CT_EMAIL, CardTag.CT_LOCATION, 23 CardTag.CT_URL, CardTag.CT_DEFINITION, CardTag.CT_TRANSLATE, 24 CardTag.CT_CONTEXTUAL_DEFINITION}) 25 @Retention(RetentionPolicy.SOURCE) 26 public @interface CardTag { 27 int CT_NONE = 0; 28 int CT_OTHER = 1; 29 int CT_HAS_ENTITY = 2; 30 int CT_BUSINESS = 3; 31 int CT_PRODUCT = 4; 32 int CT_CONTACT = 5; 33 int CT_EMAIL = 6; 34 int CT_LOCATION = 7; 35 int CT_URL = 8; 36 int CT_DEFINITION = 9; 37 int CT_TRANSLATE = 10; 38 int CT_CONTEXTUAL_DEFINITION = 11; 39 int NUM_ENTRIES = 12; 40 } 41 42 private final boolean mIsNetworkUnavailable; 43 private final int mResponseCode; 44 private final String mSearchTerm; 45 private final String mDisplayText; 46 private final String mAlternateTerm; 47 private final String mMid; 48 private final boolean mDoPreventPreload; 49 private final int mSelectionStartAdjust; 50 private final int mSelectionEndAdjust; 51 private final String mContextLanguage; 52 private final String mThumbnailUrl; 53 private final String mCaption; 54 private final String mQuickActionUri; 55 @QuickActionCategory 56 private final int mQuickActionCategory; 57 private final long mLoggedEventId; 58 private final String mSearchUrlFull; 59 private final String mSearchUrlPreload; 60 @CardTag 61 private final int mCardTagEnum; 62 63 /** 64 * Called in response to the 65 * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method. 66 * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all other 67 * parameters should be ignored. 68 * @param responseCode The HTTP response code. If the code is not OK, the query should be 69 * ignored. 70 * @param searchTerm The term to use in our subsequent search. 71 * @param displayText The text to display in our UX. 72 * @param alternateTerm The alternate term to display on the results page. 73 * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string. 74 * A MID is a unique identifier for an entity in the Search Knowledge Graph. 75 * @param doPreventPreload Whether we should prevent preloading on this search. 76 * @param selectionStartAdjust A positive number of characters that the start of the existing 77 * selection should be expanded by. 78 * @param selectionEndAdjust A positive number of characters that the end of the existing 79 * selection should be expanded by. 80 * @param contextLanguage The language of the original search term, or an empty string. 81 * @param thumbnailUrl The URL of the thumbnail to display in our UX. 82 * @param caption The caption to display. 83 * @param quickActionUri The URI for the intent associated with the quick action. 84 * @param quickActionCategory The {@link QuickActionCategory} for the quick action. 85 * @param loggedEventId The EventID logged by the server, which should be recorded and sent back 86 * to the server along with user action results in a subsequent request. 87 * @param searchUrlFull The URL for the full search to present in the overlay, or empty. 88 * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. 89 * @param cardTagEnum A {@link CardTag} enumeration indicating what kind of card was returned, 90 * or {@code 0} if no card was returned. 91 */ ResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, final String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl, final String caption, final String quickActionUri, @QuickActionCategory final int quickActionCategory, final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, @CardTag final int cardTagEnum)92 private ResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, 93 final String searchTerm, final String displayText, final String alternateTerm, 94 final String mid, boolean doPreventPreload, int selectionStartAdjust, 95 int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl, 96 final String caption, final String quickActionUri, 97 @QuickActionCategory final int quickActionCategory, final long loggedEventId, 98 final String searchUrlFull, final String searchUrlPreload, 99 @CardTag final int cardTagEnum) { 100 mIsNetworkUnavailable = isNetworkUnavailable; 101 mResponseCode = responseCode; 102 mSearchTerm = searchTerm; 103 mDisplayText = displayText; 104 mAlternateTerm = alternateTerm; 105 mMid = mid; 106 mDoPreventPreload = doPreventPreload; 107 mSelectionStartAdjust = selectionStartAdjust; 108 mSelectionEndAdjust = selectionEndAdjust; 109 mContextLanguage = contextLanguage; 110 mThumbnailUrl = thumbnailUrl; 111 mCaption = caption; 112 mQuickActionUri = quickActionUri; 113 mQuickActionCategory = quickActionCategory; 114 mLoggedEventId = loggedEventId; 115 mSearchUrlFull = searchUrlFull; 116 mSearchUrlPreload = searchUrlPreload; 117 mCardTagEnum = cardTagEnum; 118 } 119 isNetworkUnavailable()120 public boolean isNetworkUnavailable() { 121 return mIsNetworkUnavailable; 122 } 123 responseCode()124 public int responseCode() { 125 return mResponseCode; 126 } 127 searchTerm()128 public String searchTerm() { 129 return mSearchTerm; 130 } 131 displayText()132 public String displayText() { 133 return mDisplayText; 134 } 135 alternateTerm()136 public String alternateTerm() { 137 return mAlternateTerm; 138 } 139 mid()140 public String mid() { 141 return mMid; 142 } 143 doPreventPreload()144 public boolean doPreventPreload() { 145 return mDoPreventPreload; 146 } 147 selectionStartAdjust()148 public int selectionStartAdjust() { 149 return mSelectionStartAdjust; 150 } 151 selectionEndAdjust()152 public int selectionEndAdjust() { 153 return mSelectionEndAdjust; 154 } 155 contextLanguage()156 public String contextLanguage() { 157 return mContextLanguage; 158 } 159 thumbnailUrl()160 public String thumbnailUrl() { 161 return mThumbnailUrl; 162 } 163 caption()164 public String caption() { 165 return mCaption; 166 } 167 quickActionUri()168 public String quickActionUri() { 169 return mQuickActionUri; 170 } 171 quickActionCategory()172 public @QuickActionCategory int quickActionCategory() { 173 return mQuickActionCategory; 174 } 175 loggedEventId()176 public long loggedEventId() { 177 return mLoggedEventId; 178 } 179 searchUrlFull()180 public String searchUrlFull() { 181 return mSearchUrlFull; 182 } 183 searchUrlPreload()184 public String searchUrlPreload() { 185 return mSearchUrlPreload; 186 } 187 cardTagEnum()188 public @CardTag int cardTagEnum() { 189 return mCardTagEnum; 190 } 191 fromCocaCardTag(int internalCocaCardTag)192 public static @CardTag int fromCocaCardTag(int internalCocaCardTag) { 193 switch (internalCocaCardTag) { 194 case 0: 195 return CardTag.CT_NONE; 196 case 43: 197 return CardTag.CT_HAS_ENTITY; 198 case 5: 199 return CardTag.CT_BUSINESS; 200 case 26: 201 return CardTag.CT_PRODUCT; 202 case 8: 203 return CardTag.CT_CONTACT; 204 case 13: 205 return CardTag.CT_EMAIL; 206 case 21: 207 return CardTag.CT_LOCATION; 208 case 40: 209 return CardTag.CT_URL; 210 case 11: 211 return CardTag.CT_DEFINITION; 212 case 39: 213 return CardTag.CT_TRANSLATE; 214 case 47: 215 return CardTag.CT_CONTEXTUAL_DEFINITION; 216 default: 217 return CardTag.CT_OTHER; 218 } 219 } 220 221 @Override toString()222 public String toString() { 223 List<String> sections = buildTextSections(); 224 return TextUtils.join(", ", sections); 225 } 226 buildTextSections()227 private List<String> buildTextSections() { 228 List<String> sections = new ArrayList<String>(); 229 if (mIsNetworkUnavailable) { 230 sections.add("Network unavailable!"); 231 } else if (mResponseCode != HttpURLConnection.HTTP_OK) { 232 sections.add("ResponseCode:" + mResponseCode); 233 } else { 234 if (mDoPreventPreload) sections.add("Preventing preload!"); 235 if (!TextUtils.isEmpty(mSearchTerm)) sections.add("Search for '" + mSearchTerm + "'"); 236 if (!TextUtils.isEmpty(mDisplayText)) { 237 sections.add("displayed as '" + mDisplayText + "'"); 238 } 239 if (!TextUtils.isEmpty(mMid)) sections.add("MID:'" + mMid + "'"); 240 if (mSelectionStartAdjust != 0 || mSelectionEndAdjust != 0) { 241 sections.add( 242 "selection adjust:" + mSelectionStartAdjust + "," + mSelectionEndAdjust); 243 } 244 if (!TextUtils.isEmpty(mContextLanguage) && mContextLanguage.equals("en")) { 245 sections.add("mContextLanguage:'" + mContextLanguage + "'"); 246 } 247 if (!TextUtils.isEmpty(mThumbnailUrl)) sections.add("has thumbnail URL"); 248 if (!TextUtils.isEmpty(mCaption)) sections.add("caption:'" + mCaption + "'"); 249 if (!TextUtils.isEmpty(mQuickActionUri)) sections.add("has Quick Action URI"); 250 if (!TextUtils.isEmpty(mQuickActionUri)) { 251 sections.add("quick Action Category:" + mQuickActionCategory); 252 } 253 if (mLoggedEventId != 0L) sections.add("has loggedEventId"); 254 if (!TextUtils.isEmpty(mSearchUrlFull)) { 255 sections.add("search Url full:'" + mSearchUrlFull + "'"); 256 } 257 if (!TextUtils.isEmpty(mSearchUrlPreload)) { 258 sections.add("search Url preload:'" + mSearchUrlPreload + "'"); 259 } 260 if (mCardTagEnum != CardTag.CT_NONE) sections.add("Card-Tag:" + mCardTagEnum); 261 } 262 return sections; 263 } 264 265 /** The builder for {@link ResolvedSearchTerm} objects. */ 266 public static class Builder { 267 private boolean mIsNetworkUnavailable; 268 private int mResponseCode; 269 private String mSearchTerm; 270 private String mDisplayText; 271 private String mAlternateTerm; 272 private String mMid; 273 private boolean mDoPreventPreload; 274 private int mSelectionStartAdjust; 275 private int mSelectionEndAdjust; 276 private String mContextLanguage; 277 private String mThumbnailUrl; 278 private String mCaption; 279 private String mQuickActionUri; 280 @QuickActionCategory 281 private int mQuickActionCategory; 282 private long mLoggedEventId; 283 private String mSearchUrlFull; 284 private String mSearchUrlPreload; 285 @CardTag 286 private int mCardTagEnum; 287 Builder(ResolvedSearchTerm resolvedSearchTerm)288 public Builder(ResolvedSearchTerm resolvedSearchTerm) { 289 mIsNetworkUnavailable = resolvedSearchTerm.mIsNetworkUnavailable; 290 mResponseCode = resolvedSearchTerm.mResponseCode; 291 mSearchTerm = resolvedSearchTerm.mSearchTerm; 292 mDisplayText = resolvedSearchTerm.mDisplayText; 293 mAlternateTerm = resolvedSearchTerm.mAlternateTerm; 294 mMid = resolvedSearchTerm.mMid; 295 mDoPreventPreload = resolvedSearchTerm.mDoPreventPreload; 296 mSelectionStartAdjust = resolvedSearchTerm.mSelectionStartAdjust; 297 mSelectionEndAdjust = resolvedSearchTerm.mSelectionEndAdjust; 298 mContextLanguage = resolvedSearchTerm.mContextLanguage; 299 mThumbnailUrl = resolvedSearchTerm.mThumbnailUrl; 300 mCaption = resolvedSearchTerm.mCaption; 301 mQuickActionUri = resolvedSearchTerm.mQuickActionUri; 302 mQuickActionCategory = resolvedSearchTerm.mQuickActionCategory; 303 mLoggedEventId = resolvedSearchTerm.mLoggedEventId; 304 mSearchUrlFull = resolvedSearchTerm.mSearchUrlFull; 305 mSearchUrlPreload = resolvedSearchTerm.mSearchUrlPreload; 306 mCardTagEnum = resolvedSearchTerm.mCardTagEnum; 307 } 308 309 /** 310 * Builds a response to the 311 * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method. 312 * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all 313 * other parameters should be ignored. 314 * @param responseCode The HTTP response code. If the code is not OK, the query should be 315 * ignored. 316 * @param searchTerm The term to use in our subsequent search. 317 * @param displayText The text to display in our UX. 318 */ Builder(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText)319 public Builder(boolean isNetworkUnavailable, int responseCode, final String searchTerm, 320 final String displayText) { 321 this(isNetworkUnavailable, responseCode, searchTerm, displayText, "", false); 322 } 323 324 /** 325 * Builds a response to the 326 * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method. 327 * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all 328 * other parameters should be ignored. 329 * @param responseCode The HTTP response code. If the code is not OK, the query should be 330 * ignored. 331 * @param searchTerm The term to use in our subsequent search. 332 * @param displayText The text to display in our UX. 333 * @param alternateTerm The alternate term to display on the results page. 334 * @param doPreventPreload Whether we should prevent preloading on this search. 335 */ Builder(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, boolean doPreventPreload)336 public Builder(boolean isNetworkUnavailable, int responseCode, final String searchTerm, 337 final String displayText, final String alternateTerm, boolean doPreventPreload) { 338 this(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, "", 339 doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0L, "", "", 340 0); 341 } 342 343 /** 344 * Builds a response to the 345 * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method. 346 * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all 347 * other parameters should be ignored. 348 * @param responseCode The HTTP response code. If the code is not OK, the query should be 349 * ignored. 350 * @param searchTerm The term to use in our subsequent search. 351 * @param displayText The text to display in our UX. 352 * @param alternateTerm The alternate term to display on the results page. 353 * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string. 354 * A MID is a unique identifier for an entity in the Search Knowledge Graph. 355 * @param doPreventPreload Whether we should prevent preloading on this search. 356 * @param selectionStartAdjust A positive number of characters that the start of the 357 * existing selection should be expanded by. 358 * @param selectionEndAdjust A positive number of characters that the end of the existing 359 * selection should be expanded by. 360 * @param contextLanguage The language of the original search term, or an empty string. 361 * @param thumbnailUrl The URL of the thumbnail to display in our UX. 362 * @param caption The caption to display. 363 * @param quickActionUri The URI for the intent associated with the quick action. 364 * @param quickActionCategory The {@link QuickActionCategory} for the quick action. 365 * @param loggedEventId The EventID logged by the server, which should be recorded and sent 366 * back to the server along with user action results in a subsequent request. 367 * @param searchUrlFull The URL for the full search to present in the overlay, or empty. 368 * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. 369 * @param cardTag The primary internal Coca card tag for the resolution, or {@code 0} if 370 * none. 371 */ Builder(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, final String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl, final String caption, final String quickActionUri, @QuickActionCategory final int quickActionCategory, final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, final int cardTag)372 public Builder(boolean isNetworkUnavailable, int responseCode, final String searchTerm, 373 final String displayText, final String alternateTerm, final String mid, 374 boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, 375 final String contextLanguage, final String thumbnailUrl, final String caption, 376 final String quickActionUri, @QuickActionCategory final int quickActionCategory, 377 final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, 378 final int cardTag) { 379 mIsNetworkUnavailable = isNetworkUnavailable; 380 mResponseCode = responseCode; 381 mSearchTerm = searchTerm; 382 mDisplayText = displayText; 383 mAlternateTerm = alternateTerm; 384 mMid = mid; 385 mDoPreventPreload = doPreventPreload; 386 mSelectionStartAdjust = selectionStartAdjust; 387 mSelectionEndAdjust = selectionEndAdjust; 388 mContextLanguage = contextLanguage; 389 mThumbnailUrl = thumbnailUrl; 390 mCaption = caption; 391 mQuickActionUri = quickActionUri; 392 mQuickActionCategory = quickActionCategory; 393 mLoggedEventId = loggedEventId; 394 mSearchUrlFull = searchUrlFull; 395 mSearchUrlPreload = searchUrlPreload; 396 mCardTagEnum = fromCocaCardTag(cardTag); 397 } 398 399 /** 400 * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all 401 * other parameters should be ignored. 402 */ setIsNetworkUnavailable(boolean isNetworkUnavailable)403 public Builder setIsNetworkUnavailable(boolean isNetworkUnavailable) { 404 mIsNetworkUnavailable = isNetworkUnavailable; 405 return this; 406 } 407 408 /** 409 * @param responseCode The HTTP response code. If the code is not OK, the query should be 410 * ignored. 411 */ setResponseCode(int responseCode)412 public Builder setResponseCode(int responseCode) { 413 mResponseCode = responseCode; 414 return this; 415 } 416 417 /** @param searchTerm The term to use in our subsequent search. */ setSearchTerm(String searchTerm)418 public Builder setSearchTerm(String searchTerm) { 419 mSearchTerm = searchTerm; 420 return this; 421 } 422 423 /** @param displayText The text to display in our UX. */ setDisplayText(String displayText)424 public Builder setDisplayText(String displayText) { 425 mDisplayText = displayText; 426 return this; 427 } 428 429 /** @param alternateTerm The alternate term to display on the results page. */ setAlternateTerm(String alternateTerm)430 public Builder setAlternateTerm(String alternateTerm) { 431 mAlternateTerm = alternateTerm; 432 return this; 433 } 434 435 /** 436 * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string. 437 * A MID is a unique identifier for an entity in the Search Knowledge Graph. 438 */ setMid(String mid)439 public Builder setMid(String mid) { 440 mMid = mid; 441 return this; 442 } 443 444 /** @param doPreventPreload Whether we should prevent preloading on this search. */ setDoPreventPreload(boolean doPreventPreload)445 public Builder setDoPreventPreload(boolean doPreventPreload) { 446 mDoPreventPreload = doPreventPreload; 447 return this; 448 } 449 450 /** 451 * @param selectionStartAdjust A positive number of characters that the start of the 452 * existing selection should be expanded by. 453 */ setSelectionStartAdjust(int selectionStartAdjust)454 public Builder setSelectionStartAdjust(int selectionStartAdjust) { 455 mSelectionStartAdjust = selectionStartAdjust; 456 return this; 457 } 458 459 /** 460 * @param selectionEndAdjust A positive number of characters that the end of the existing 461 * selection should be expanded by. 462 */ setSelectionEndAdjust(int selectionEndAdjust)463 public Builder setSelectionEndAdjust(int selectionEndAdjust) { 464 mSelectionEndAdjust = selectionEndAdjust; 465 return this; 466 } 467 468 /** @param contextLanguage The language of the original search term, or an empty string. */ setContextLanguage(String contextLanguage)469 public Builder setContextLanguage(String contextLanguage) { 470 mContextLanguage = contextLanguage; 471 return this; 472 } 473 474 /** @param thumbnailUrl The URL of the thumbnail to display in our UX. */ setThumbnailUrl(String thumbnailUrl)475 public Builder setThumbnailUrl(String thumbnailUrl) { 476 mThumbnailUrl = thumbnailUrl; 477 return this; 478 } 479 480 /** @param caption The caption to display. */ setCaption(String caption)481 public Builder setCaption(String caption) { 482 mCaption = caption; 483 return this; 484 } 485 486 /** @param quickActionUri The URI for the intent associated with the quick action. */ setQuickActionUri(String quickActionUri)487 public Builder setQuickActionUri(String quickActionUri) { 488 mQuickActionUri = quickActionUri; 489 return this; 490 } 491 492 /** @param quickActionCategory The {@link QuickActionCategory} for the quick action. */ setQuickActionCategory(@uickActionCategory int quickActionCategory)493 public Builder setQuickActionCategory(@QuickActionCategory int quickActionCategory) { 494 mQuickActionCategory = quickActionCategory; 495 return this; 496 } 497 setLoggedEventId(long loggedEventId)498 public Builder setLoggedEventId(long loggedEventId) { 499 mLoggedEventId = loggedEventId; 500 return this; 501 } 502 503 /** @param searchUrlFull The URL for the full search to present in the overlay, or empty. */ setSearchUrlFull(String searchUrlFull)504 public Builder setSearchUrlFull(String searchUrlFull) { 505 mSearchUrlFull = searchUrlFull; 506 return this; 507 } 508 509 /** @param searchUrlPreload The URL for the search to preload into the overlay, or empty. */ setSearchUrlPreload(String searchUrlPreload)510 public Builder setSearchUrlPreload(String searchUrlPreload) { 511 mSearchUrlPreload = searchUrlPreload; 512 return this; 513 } 514 515 /** 516 * @param cardTagEnum The primary internal Coca card tag for the resolution, or {@code 0} if 517 * none. 518 */ setCardTagEnum(@ardTag int cardTagEnum)519 public Builder setCardTagEnum(@CardTag int cardTagEnum) { 520 mCardTagEnum = cardTagEnum; 521 return this; 522 } 523 524 /** 525 * Builds the {@link ResolvedSearchTerm} based on the params passed into the constructor 526 * of this builder, plus whatever settings have been established. 527 * @return The {@link ResolvedSearchTerm}, which represents all the results sent back by 528 * the server for the Resolve request. 529 */ build()530 public ResolvedSearchTerm build() { 531 return new ResolvedSearchTerm(mIsNetworkUnavailable, mResponseCode, mSearchTerm, 532 mDisplayText, mAlternateTerm, mMid, mDoPreventPreload, mSelectionStartAdjust, 533 mSelectionEndAdjust, mContextLanguage, mThumbnailUrl, mCaption, mQuickActionUri, 534 mQuickActionCategory, mLoggedEventId, mSearchUrlFull, mSearchUrlPreload, 535 mCardTagEnum); 536 } 537 } 538 } 539