• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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.omnibox;
6 
7 import android.text.TextUtils;
8 
9 import com.google.common.annotations.VisibleForTesting;
10 
11 import org.chromium.base.CalledByNative;
12 import org.chromium.chrome.browser.profiles.Profile;
13 import org.chromium.content_public.browser.WebContents;
14 
15 import java.util.ArrayList;
16 import java.util.List;
17 
18 /**
19  * Bridge to the native AutocompleteControllerAndroid.
20  */
21 public class AutocompleteController {
22     private long mNativeAutocompleteControllerAndroid;
23     private long mCurrentNativeAutocompleteResult;
24     private final OnSuggestionsReceivedListener mListener;
25 
26     /**
27      * Listener for receiving OmniboxSuggestions.
28      */
29     public static interface OnSuggestionsReceivedListener {
onSuggestionsReceived(List<OmniboxSuggestion> suggestions, String inlineAutocompleteText)30         void onSuggestionsReceived(List<OmniboxSuggestion> suggestions,
31                 String inlineAutocompleteText);
32     }
33 
AutocompleteController(OnSuggestionsReceivedListener listener)34     public AutocompleteController(OnSuggestionsReceivedListener listener) {
35         this(null, listener);
36     }
37 
AutocompleteController(Profile profile, OnSuggestionsReceivedListener listener)38     public AutocompleteController(Profile profile, OnSuggestionsReceivedListener listener) {
39         if (profile != null) {
40             mNativeAutocompleteControllerAndroid = nativeInit(profile);
41         }
42         mListener = listener;
43     }
44 
45     /**
46      * Resets the underlying autocomplete controller based on the specified profile.
47      *
48      * <p>This will implicitly stop the autocomplete suggestions, so
49      * {@link #start(Profile, String, String, boolean)} must be called again to start them flowing
50      * again.  This should not be an issue as changing profiles should not normally occur while
51      * waiting on omnibox suggestions.
52      *
53      * @param profile The profile to reset the AutocompleteController with.
54      */
setProfile(Profile profile)55     public void setProfile(Profile profile) {
56         stop(true);
57         if (profile == null) {
58             mNativeAutocompleteControllerAndroid = 0;
59             return;
60         }
61 
62         mNativeAutocompleteControllerAndroid = nativeInit(profile);
63     }
64 
65     /**
66      * Starts querying for omnibox suggestions for a given text.
67      *
68      * @param profile The profile to use for starting the AutocompleteController
69      * @param url The URL of the current tab, used to suggest query refinements.
70      * @param text The text to query autocomplete suggestions for.
71      * @param preventInlineAutocomplete Whether autocomplete suggestions should be prevented.
72      */
start(Profile profile, String url, String text, boolean preventInlineAutocomplete)73     public void start(Profile profile, String url, String text, boolean preventInlineAutocomplete) {
74         if (profile == null || TextUtils.isEmpty(url)) return;
75 
76         mNativeAutocompleteControllerAndroid = nativeInit(profile);
77         // Initializing the native counterpart might still fail.
78         if (mNativeAutocompleteControllerAndroid != 0) {
79             nativeStart(mNativeAutocompleteControllerAndroid, text, null, url,
80                     preventInlineAutocomplete, false, false, true);
81         }
82     }
83 
84     /**
85      * Given some string |text| that the user wants to use for navigation, determines how it should
86      * be interpreted. This is a fallback in case the user didn't select a visible suggestion (e.g.
87      * the user pressed enter before omnibox suggestions had been shown).
88      *
89      * Note: this updates the internal state of the autocomplete controller just as start() does.
90      * Future calls that reference autocomplete results by index, e.g. onSuggestionSelected(),
91      * should reference the returned suggestion by index 0.
92      *
93      * @param text The user's input text to classify (i.e. what they typed in the omnibox)
94      * @return The OmniboxSuggestion specifying where to navigate, the transition type, etc. May
95      *         be null if the input is invalid.
96      */
classify(String text)97     public OmniboxSuggestion classify(String text) {
98         return nativeClassify(mNativeAutocompleteControllerAndroid, text);
99     }
100 
101     /**
102      * Starts a query for suggestions before any input is available from the user.
103      *
104      * @param profile The profile to use for starting the AutocompleteController.
105      * @param omniboxText The text displayed in the omnibox.
106      * @param url The url of the currently loaded web page.
107      * @param isQueryInOmnibox Whether the location bar is currently showing a search query.
108      * @param focusedFromFakebox Whether the user entered the omnibox by tapping the fakebox on the
109      *                           native NTP. This should be false on all other pages.
110      */
startZeroSuggest(Profile profile, String omniboxText, String url, boolean isQueryInOmnibox, boolean focusedFromFakebox)111     public void startZeroSuggest(Profile profile, String omniboxText, String url,
112             boolean isQueryInOmnibox, boolean focusedFromFakebox) {
113         if (profile == null || TextUtils.isEmpty(url)) return;
114         mNativeAutocompleteControllerAndroid = nativeInit(profile);
115         if (mNativeAutocompleteControllerAndroid != 0) {
116             nativeStartZeroSuggest(mNativeAutocompleteControllerAndroid, omniboxText, url,
117                     isQueryInOmnibox, focusedFromFakebox);
118         }
119     }
120 
121     /**
122      * Stops generating autocomplete suggestions for the currently specified text from
123      * {@link #start(Profile,String, String, boolean)}.
124      *
125      * <p>
126      * Calling this method with {@code false}, will result in
127      * {@link #onSuggestionsReceived(List, String, long)} being called with an empty
128      * result set.
129      *
130      * @param clear Whether to clear the most recent autocomplete results.
131      */
stop(boolean clear)132     public void stop(boolean clear) {
133         mCurrentNativeAutocompleteResult = 0;
134         if (mNativeAutocompleteControllerAndroid != 0) {
135             nativeStop(mNativeAutocompleteControllerAndroid, clear);
136         }
137     }
138 
139     /**
140      * Resets session for autocomplete controller. This happens every time we start typing
141      * new input into the omnibox.
142      */
resetSession()143     public void resetSession() {
144         if (mNativeAutocompleteControllerAndroid != 0) {
145             nativeResetSession(mNativeAutocompleteControllerAndroid);
146         }
147     }
148 
149     /**
150      * Deletes an omnibox suggestion, if possible.
151      * @param position The position at which the suggestion is located.
152      */
deleteSuggestion(int position)153     public void deleteSuggestion(int position) {
154         if (mNativeAutocompleteControllerAndroid != 0) {
155             nativeDeleteSuggestion(mNativeAutocompleteControllerAndroid, position);
156         }
157     }
158 
159     /**
160      * @return Native pointer to current autocomplete results.
161      */
162     @VisibleForTesting
getCurrentNativeAutocompleteResult()163     public long getCurrentNativeAutocompleteResult() {
164         return mCurrentNativeAutocompleteResult;
165     }
166 
167     @CalledByNative
onSuggestionsReceived( List<OmniboxSuggestion> suggestions, String inlineAutocompleteText, long currentNativeAutocompleteResult)168     protected void onSuggestionsReceived(
169             List<OmniboxSuggestion> suggestions,
170             String inlineAutocompleteText,
171             long currentNativeAutocompleteResult) {
172         mCurrentNativeAutocompleteResult = currentNativeAutocompleteResult;
173 
174         // Notify callbacks of suggestions.
175         mListener.onSuggestionsReceived(suggestions, inlineAutocompleteText);
176     }
177 
178     @CalledByNative
notifyNativeDestroyed()179     private void notifyNativeDestroyed() {
180         mNativeAutocompleteControllerAndroid = 0;
181     }
182 
183     /**
184      * Called whenever a navigation happens from the omnibox to record metrics about the user's
185      * interaction with the omnibox.
186      *
187      * @param selectedIndex The index of the suggestion that was selected.
188      * @param type The type of the selected suggestion.
189      * @param currentPageUrl The URL of the current page.
190      * @param focusedFromFakebox Whether the user entered the omnibox by tapping the fakebox on the
191      *                           native NTP. This should be false on all other pages.
192      * @param elapsedTimeSinceModified The number of ms that passed between the user first
193      *                                 modifying text in the omnibox and selecting a suggestion.
194      * @param webContents The web contents for the tab where the selected suggestion will be shown.
195      */
onSuggestionSelected(int selectedIndex, OmniboxSuggestion.Type type, String currentPageUrl, boolean isQueryInOmnibox, boolean focusedFromFakebox, long elapsedTimeSinceModified, WebContents webContents)196     protected void onSuggestionSelected(int selectedIndex, OmniboxSuggestion.Type type,
197             String currentPageUrl, boolean isQueryInOmnibox, boolean focusedFromFakebox,
198             long elapsedTimeSinceModified, WebContents webContents) {
199         nativeOnSuggestionSelected(mNativeAutocompleteControllerAndroid, selectedIndex,
200                 currentPageUrl, isQueryInOmnibox, focusedFromFakebox, elapsedTimeSinceModified,
201                 webContents);
202     }
203 
204     @CalledByNative
createOmniboxSuggestionList(int size)205     private static List<OmniboxSuggestion> createOmniboxSuggestionList(int size) {
206         return new ArrayList<OmniboxSuggestion>(size);
207     }
208 
209     @CalledByNative
addOmniboxSuggestionToList(List<OmniboxSuggestion> suggestionList, OmniboxSuggestion suggestion)210     private static void addOmniboxSuggestionToList(List<OmniboxSuggestion> suggestionList,
211             OmniboxSuggestion suggestion) {
212         suggestionList.add(suggestion);
213     }
214 
215     @CalledByNative
buildOmniboxSuggestion(int nativeType, int relevance, int transition, String text, String description, String answerContents, String answerType, String fillIntoEdit, String url, String formattedUrl, boolean isStarred, boolean isDeletable)216     private static OmniboxSuggestion buildOmniboxSuggestion(int nativeType, int relevance,
217             int transition, String text, String description, String answerContents,
218             String answerType, String fillIntoEdit, String url, String formattedUrl,
219             boolean isStarred, boolean isDeletable) {
220         return new OmniboxSuggestion(nativeType, relevance, transition, text, description,
221                 answerContents, answerType, fillIntoEdit, url, formattedUrl, isStarred,
222                 isDeletable);
223     }
224 
225     /**
226      * Updates aqs parameters on the selected match that we will navigate to and returns the
227      * updated URL. |selected_index| is the position of the selected match and
228      * |elapsed_time_since_input_change| is the time in ms between the first typed input and match
229      * selection.
230      *
231      * @param selectedIndex The index of the autocomplete entry selected.
232      * @param elapsedTimeSinceInputChange The number of ms between the time the user started
233      *                                    typing in the omnibox and the time the user has selected
234      *                                    a suggestion.
235      * @return The url to navigate to for this match with aqs parameter updated, if we are
236      *         making a Google search query.
237      */
updateMatchDestinationUrl(int selectedIndex, long elapsedTimeSinceInputChange)238     public String updateMatchDestinationUrl(int selectedIndex, long elapsedTimeSinceInputChange) {
239         return nativeUpdateMatchDestinationURL(mNativeAutocompleteControllerAndroid, selectedIndex,
240                 elapsedTimeSinceInputChange);
241     }
242 
243     /**
244      * @param query User input text.
245      * @return The top synchronous suggestion from the autocomplete controller.
246      */
getTopSynchronousMatch(String query)247     public OmniboxSuggestion getTopSynchronousMatch(String query) {
248         return nativeGetTopSynchronousMatch(mNativeAutocompleteControllerAndroid, query);
249     }
250 
251     @VisibleForTesting
nativeInit(Profile profile)252     protected native long nativeInit(Profile profile);
nativeStart(long nativeAutocompleteControllerAndroid, String text, String desiredTld, String currentUrl, boolean preventInlineAutocomplete, boolean preferKeyword, boolean allowExactKeywordMatch, boolean wantAsynchronousMatches)253     private native void nativeStart(long nativeAutocompleteControllerAndroid, String text,
254             String desiredTld, String currentUrl, boolean preventInlineAutocomplete,
255             boolean preferKeyword, boolean allowExactKeywordMatch, boolean wantAsynchronousMatches);
nativeClassify(long nativeAutocompleteControllerAndroid, String text)256     private native OmniboxSuggestion nativeClassify(long nativeAutocompleteControllerAndroid,
257             String text);
nativeStop(long nativeAutocompleteControllerAndroid, boolean clearResults)258     private native void nativeStop(long nativeAutocompleteControllerAndroid, boolean clearResults);
nativeResetSession(long nativeAutocompleteControllerAndroid)259     private native void nativeResetSession(long nativeAutocompleteControllerAndroid);
nativeOnSuggestionSelected(long nativeAutocompleteControllerAndroid, int selectedIndex, String currentPageUrl, boolean isQueryInOmnibox, boolean focusedFromFakebox, long elapsedTimeSinceModified, WebContents webContents)260     private native void nativeOnSuggestionSelected(long nativeAutocompleteControllerAndroid,
261             int selectedIndex, String currentPageUrl, boolean isQueryInOmnibox,
262             boolean focusedFromFakebox, long elapsedTimeSinceModified, WebContents webContents);
nativeStartZeroSuggest(long nativeAutocompleteControllerAndroid, String omniboxText, String currentUrl, boolean isQueryInOmnibox, boolean focusedFromFakebox)263     private native void nativeStartZeroSuggest(long nativeAutocompleteControllerAndroid,
264             String omniboxText, String currentUrl, boolean isQueryInOmnibox,
265             boolean focusedFromFakebox);
nativeDeleteSuggestion(long nativeAutocompleteControllerAndroid, int selectedIndex)266     private native void nativeDeleteSuggestion(long nativeAutocompleteControllerAndroid,
267             int selectedIndex);
nativeUpdateMatchDestinationURL(long nativeAutocompleteControllerAndroid, int selectedIndex, long elapsedTimeSinceInputChange)268     private native String nativeUpdateMatchDestinationURL(long nativeAutocompleteControllerAndroid,
269             int selectedIndex, long elapsedTimeSinceInputChange);
nativeGetTopSynchronousMatch( long nativeAutocompleteControllerAndroid, String query)270     private native OmniboxSuggestion nativeGetTopSynchronousMatch(
271             long nativeAutocompleteControllerAndroid, String query);
272 
273     /**
274      * Given a search query, this will attempt to see if the query appears to be portion of a
275      * properly formed URL.  If it appears to be a URL, this will return the fully qualified
276      * version (i.e. including the scheme, etc...).  If the query does not appear to be a URL,
277      * this will return null.
278      *
279      * @param query The query to be expanded into a fully qualified URL if appropriate.
280      * @return The fully qualified URL or null.
281      */
nativeQualifyPartialURLQuery(String query)282     public static native String nativeQualifyPartialURLQuery(String query);
283 
284     /**
285      * Sends a zero suggest request to the server in order to pre-populate the result cache.
286      */
nativePrefetchZeroSuggestResults()287     public static native void nativePrefetchZeroSuggestResults();
288 }
289