Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / android / shell / java / src / org / chromium / chrome / shell / omnibox / SuggestionPopup.java
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.shell.omnibox;
6
7 import android.content.Context;
8 import android.graphics.Rect;
9 import android.os.Handler;
10 import android.text.Editable;
11 import android.text.TextUtils;
12 import android.text.TextWatcher;
13 import android.view.View;
14 import android.view.View.OnLayoutChangeListener;
15 import android.widget.AdapterView;
16 import android.widget.AdapterView.OnItemClickListener;
17 import android.widget.EditText;
18 import android.widget.ListPopupWindow;
19 import android.widget.PopupWindow.OnDismissListener;
20
21
22 import org.chromium.chrome.browser.omnibox.AutocompleteController;
23 import org.chromium.chrome.browser.omnibox.AutocompleteController.OnSuggestionsReceivedListener;
24 import org.chromium.chrome.browser.omnibox.OmniboxSuggestion;
25 import org.chromium.chrome.shell.ChromeShellActivity;
26 import org.chromium.chrome.shell.ChromeShellToolbar;
27 import org.chromium.chrome.shell.R;
28
29 import java.util.List;
30
31 /**
32  * Displays suggestions for the text that is entered to the ChromeShell URL field.
33  */
34 public class SuggestionPopup implements OnSuggestionsReceivedListener, TextWatcher {
35     private static final long SUGGESTION_START_DELAY_MS = 30;
36
37     private final Context mContext;
38     private final EditText mUrlField;
39     private final ChromeShellToolbar mToolbar;
40     private final AutocompleteController mAutocomplete;
41
42     private boolean mHasStartedNewOmniboxEditSession;
43     private Runnable mRequestSuggestions;
44     private ListPopupWindow mSuggestionsPopup;
45     private SuggestionArrayAdapter mSuggestionArrayAdapter;
46     private int mSuggestionsPopupItemsCount;
47
48     /**
49      * Initializes a suggestion popup that will track urlField value and display suggestions based
50      * on that value.
51      */
52     public SuggestionPopup(Context context, EditText urlField, ChromeShellToolbar toolbar) {
53         mContext = context;
54         mUrlField = urlField;
55         mToolbar = toolbar;
56         mAutocomplete = new AutocompleteController(this);
57         OnLayoutChangeListener listener = new OnLayoutChangeListener() {
58             @Override
59             public void onLayoutChange(View v, int left, int top, int right, int bottom,
60                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
61                 if (mSuggestionsPopup == null || !mSuggestionsPopup.isShowing()) return;
62                 mSuggestionsPopup.setWidth(mToolbar.getWidth());
63                 mSuggestionsPopup.setHeight(getSuggestionPopupHeight());
64                 mSuggestionsPopup.show();
65             }
66         };
67         mUrlField.addOnLayoutChangeListener(listener);
68     }
69
70     private void navigateToSuggestion(int position) {
71         mToolbar.getCurrentTab().loadUrlWithSanitization(
72                 mSuggestionArrayAdapter.getItem(position).getUrl());
73         mUrlField.clearFocus();
74         mToolbar.setKeyboardVisibilityForUrl(false);
75         mToolbar.getCurrentTab().getView().requestFocus();
76         dismissPopup();
77     }
78
79     public void dismissPopup() {
80         if (mSuggestionsPopup != null) {
81             mSuggestionsPopup.dismiss();
82             mSuggestionsPopup = null;
83         }
84     }
85
86     /**
87      * Stops the autocomplete controller and closes the suggestion popup.
88      */
89     public void hideSuggestions() {
90         stopAutocomplete(true);
91         dismissPopup();
92     }
93
94     /**
95      * Signals the autocomplete controller to stop generating suggestions and
96      * cancels the queued task to start the autocomplete controller, if any.
97      *
98      * @param clear Whether to clear the most recent autocomplete results.
99      */
100     private void stopAutocomplete(boolean clear) {
101         if (mAutocomplete != null) mAutocomplete.stop(clear);
102         if (mRequestSuggestions != null) mRequestSuggestions = null;
103     }
104
105     private int getSuggestionPopupHeight() {
106         Rect appRect = new Rect();
107         ((ChromeShellActivity) mContext).getWindow().getDecorView()
108                 .getWindowVisibleDisplayFrame(appRect);
109         int dropDownItemHeight = mContext.getResources()
110                 .getDimensionPixelSize(R.dimen.dropdown_item_height);
111         // Applying margin height equal to |dropDownItemHeight| if constrained by app rect.
112         int popupHeight = appRect.height() - dropDownItemHeight;
113         if (mSuggestionsPopup != null) {
114             int height = mSuggestionsPopupItemsCount * dropDownItemHeight;
115             if (height < popupHeight)
116                 popupHeight = height;
117         }
118         return popupHeight;
119     }
120
121     // OnSuggestionsReceivedListener implementation
122     @Override
123     public void onSuggestionsReceived(List<OmniboxSuggestion> suggestions,
124             String inlineAutocompleteText) {
125         if (!mUrlField.isFocused() || suggestions.isEmpty())
126             return;
127         mSuggestionsPopupItemsCount = suggestions.size();
128         if (mSuggestionsPopup == null) {
129             mSuggestionsPopup = new ListPopupWindow(
130                     mContext, null, android.R.attr.autoCompleteTextViewStyle);
131             mSuggestionsPopup.setOnDismissListener(new OnDismissListener() {
132                 @Override
133                 public void onDismiss() {
134                     mHasStartedNewOmniboxEditSession = false;
135                     mSuggestionArrayAdapter = null;
136                 }
137             });
138         }
139         mSuggestionsPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED);
140         mSuggestionsPopup.setWidth(mToolbar.getWidth());
141         mSuggestionArrayAdapter =
142                 new SuggestionArrayAdapter(mContext, R.layout.dropdown_item, suggestions,
143                         mUrlField);
144         mSuggestionsPopup.setHeight(getSuggestionPopupHeight());
145         mSuggestionsPopup.setAdapter(mSuggestionArrayAdapter);
146         mSuggestionsPopup.setAnchorView(mToolbar);
147         mSuggestionsPopup.setOnItemClickListener(new OnItemClickListener() {
148             @Override
149             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
150                 navigateToSuggestion(position);
151             }
152         });
153         mSuggestionsPopup.show();
154     }
155
156     // TextWatcher implementation
157
158     @Override
159     public void afterTextChanged(final Editable editableText) {
160         if (!mUrlField.hasFocus()) return;
161         if (!mHasStartedNewOmniboxEditSession) {
162             mAutocomplete.resetSession();
163             mHasStartedNewOmniboxEditSession = true;
164         }
165
166         stopAutocomplete(false);
167         if (TextUtils.isEmpty(editableText)) {
168             dismissPopup();
169         } else {
170             assert mRequestSuggestions == null : "Multiple omnibox requests in flight.";
171             mRequestSuggestions = new Runnable() {
172                 @Override
173                 public void run() {
174                     // TODO(aurimas): Create new tab if none exists.
175                     if (mToolbar.getCurrentTab() == null) return;
176                     mRequestSuggestions = null;
177                     mAutocomplete.start(
178                             mToolbar.getCurrentTab().getProfile(),
179                             mToolbar.getCurrentTab().getUrl(),
180                             editableText.toString(), false);
181                 }
182             };
183             new Handler().postDelayed(mRequestSuggestions, SUGGESTION_START_DELAY_MS);
184         }
185     }
186
187     @Override
188     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
189         mRequestSuggestions = null;
190     }
191
192     @Override
193     public void onTextChanged(CharSequence s, int start, int before, int count) {
194     }
195 }