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