Upstream version 10.39.225.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,
53             ChromeShellToolbar toolbar) {
54         mContext = context;
55         mUrlField = urlField;
56         mToolbar = toolbar;
57         mAutocomplete = new AutocompleteController(this);
58         OnLayoutChangeListener listener = new OnLayoutChangeListener() {
59             @Override
60             public void onLayoutChange(View v, int left, int top, int right, int bottom,
61                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
62                 if (mSuggestionsPopup == null || !mSuggestionsPopup.isShowing()) return;
63                 mSuggestionsPopup.setWidth(mUrlField.getWidth());
64                 mSuggestionsPopup.setHeight(getSuggestionPopupHeight());
65                 mSuggestionsPopup.show();
66             }
67         };
68         mUrlField.addOnLayoutChangeListener(listener);
69     }
70
71     private void navigateToSuggestion(int position) {
72         mToolbar.getCurrentTab().loadUrlWithSanitization(
73                 mSuggestionArrayAdapter.getItem(position).getUrl());
74         mUrlField.clearFocus();
75         mToolbar.setKeyboardVisibilityForUrl(false);
76         mToolbar.getCurrentTab().getView().requestFocus();
77         dismissPopup();
78     }
79
80     public void dismissPopup() {
81         if (mSuggestionsPopup != null) {
82             mSuggestionsPopup.dismiss();
83             mSuggestionsPopup = null;
84         }
85     }
86
87     /**
88      * Stops the autocomplete controller and closes the suggestion popup.
89      */
90     public void hideSuggestions() {
91         stopAutocomplete(true);
92         dismissPopup();
93     }
94
95     /**
96      * Signals the autocomplete controller to stop generating suggestions and
97      * cancels the queued task to start the autocomplete controller, if any.
98      *
99      * @param clear Whether to clear the most recent autocomplete results.
100      */
101     private void stopAutocomplete(boolean clear) {
102         if (mAutocomplete != null) mAutocomplete.stop(clear);
103         if (mRequestSuggestions != null) mRequestSuggestions = null;
104     }
105
106     private int getSuggestionPopupHeight() {
107         Rect appRect = new Rect();
108         ((ChromeShellActivity) mContext).getWindow().getDecorView().
109                 getWindowVisibleDisplayFrame(appRect);
110         int dropDownItemHeight = mContext.getResources().
111                 getDimensionPixelSize(R.dimen.dropdown_item_height);
112         // Applying margin height equal to |dropDownItemHeight| if constrained by app rect.
113         int popupHeight = appRect.height() - dropDownItemHeight;
114         if (mSuggestionsPopup != null) {
115             int height = mSuggestionsPopupItemsCount * dropDownItemHeight;
116             if (height < popupHeight)
117                 popupHeight = height;
118         }
119         return popupHeight;
120     }
121
122     // OnSuggestionsReceivedListener implementation
123     @Override
124     public void onSuggestionsReceived(List<OmniboxSuggestion> suggestions,
125             String inlineAutocompleteText) {
126         if (!mUrlField.isFocused() || suggestions.isEmpty())
127             return;
128         mSuggestionsPopupItemsCount = suggestions.size();
129         if (mSuggestionsPopup == null) {
130             mSuggestionsPopup = new ListPopupWindow(
131                     mContext, null, android.R.attr.autoCompleteTextViewStyle);
132             mSuggestionsPopup.setOnDismissListener(new OnDismissListener() {
133                 @Override
134                 public void onDismiss() {
135                     mHasStartedNewOmniboxEditSession = false;
136                     mSuggestionArrayAdapter = null;
137                 }
138             });
139         }
140         mSuggestionsPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED);
141         mSuggestionsPopup.setWidth(mUrlField.getWidth());
142         mSuggestionArrayAdapter =
143                 new SuggestionArrayAdapter(mContext, R.layout.dropdown_item, suggestions,
144                         mUrlField);
145         mSuggestionsPopup.setHeight(getSuggestionPopupHeight());
146         mSuggestionsPopup.setAdapter(mSuggestionArrayAdapter);
147         mSuggestionsPopup.setAnchorView(mUrlField);
148         mSuggestionsPopup.setOnItemClickListener(new OnItemClickListener() {
149             @Override
150             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
151                 navigateToSuggestion(position);
152             }
153         });
154         mSuggestionsPopup.show();
155     }
156
157     // TextWatcher implementation
158
159     @Override
160     public void afterTextChanged(final Editable editableText) {
161         if (!mUrlField.hasFocus()) return;
162         if (!mHasStartedNewOmniboxEditSession) {
163             mAutocomplete.resetSession();
164             mHasStartedNewOmniboxEditSession = true;
165         }
166
167         stopAutocomplete(false);
168         if (TextUtils.isEmpty(editableText)) {
169             dismissPopup();
170         } else {
171             assert mRequestSuggestions == null : "Multiple omnibox requests in flight.";
172             mRequestSuggestions = new Runnable() {
173                 @Override
174                 public void run() {
175                     mRequestSuggestions = null;
176                     mAutocomplete.start(
177                             mToolbar.getCurrentTab().getProfile(),
178                             mToolbar.getCurrentTab().getUrl(),
179                             editableText.toString(), false);
180                 }
181             };
182             new Handler().postDelayed(mRequestSuggestions, SUGGESTION_START_DELAY_MS);
183         }
184     }
185
186     @Override
187     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
188         mRequestSuggestions = null;
189     }
190
191     @Override
192     public void onTextChanged(CharSequence s, int start, int before, int count) {
193     }
194 }