mobile/android/base/home/SearchEngineRow.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 package org.mozilla.gecko.home;
     8 import org.mozilla.gecko.R;
     9 import org.mozilla.gecko.Telemetry;
    10 import org.mozilla.gecko.TelemetryContract;
    11 import org.mozilla.gecko.home.BrowserSearch.OnEditSuggestionListener;
    12 import org.mozilla.gecko.home.BrowserSearch.OnSearchListener;
    13 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
    14 import org.mozilla.gecko.util.StringUtils;
    15 import org.mozilla.gecko.widget.AnimatedHeightLayout;
    16 import org.mozilla.gecko.widget.FaviconView;
    17 import org.mozilla.gecko.widget.FlowLayout;
    19 import android.content.Context;
    20 import android.util.AttributeSet;
    21 import android.view.KeyEvent;
    22 import android.view.LayoutInflater;
    23 import android.view.View;
    24 import android.view.animation.AlphaAnimation;
    25 import android.widget.ImageView;
    26 import android.widget.LinearLayout;
    27 import android.widget.TextView;
    29 import java.util.EnumSet;
    31 class SearchEngineRow extends AnimatedHeightLayout {
    32     // Duration for fade-in animation
    33     private static final int ANIMATION_DURATION = 250;
    35     // Inner views
    36     private final FlowLayout mSuggestionView;
    37     private final FaviconView mIconView;
    38     private final LinearLayout mUserEnteredView;
    39     private final TextView mUserEnteredTextView;
    41     // Inflater used when updating from suggestions
    42     private final LayoutInflater mInflater;
    44     // Search engine associated with this view
    45     private SearchEngine mSearchEngine;
    47     // Event listeners for suggestion views
    48     private final OnClickListener mClickListener;
    49     private final OnLongClickListener mLongClickListener;
    51     // On URL open listener
    52     private OnUrlOpenListener mUrlOpenListener;
    54     // On search listener
    55     private OnSearchListener mSearchListener;
    57     // On edit suggestion listener
    58     private OnEditSuggestionListener mEditSuggestionListener;
    60     // Selected suggestion view
    61     private int mSelectedView = 0;
    63     public SearchEngineRow(Context context) {
    64         this(context, null);
    65     }
    67     public SearchEngineRow(Context context, AttributeSet attrs) {
    68         this(context, attrs, 0);
    69     }
    71     public SearchEngineRow(Context context, AttributeSet attrs, int defStyle) {
    72         super(context, attrs, defStyle);
    74         mClickListener = new OnClickListener() {
    75             @Override
    76             public void onClick(View v) {
    77                 final String suggestion = getSuggestionTextFromView(v);
    79                 // If we're not clicking the user-entered view (the first suggestion item)
    80                 // and the search matches a URL pattern, go to that URL. Otherwise, do a
    81                 // search for the term.
    82                 if (v != mUserEnteredView && !StringUtils.isSearchQuery(suggestion, false)) {
    83                     if (mUrlOpenListener != null) {
    84                         Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "url");
    86                         mUrlOpenListener.onUrlOpen(suggestion, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
    87                     }
    88                 } else if (mSearchListener != null) {
    89                     if (v == mUserEnteredView) {
    90                         Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "user");
    91                     } else {
    92                         Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "engine");
    93                     }
    94                     mSearchListener.onSearch(mSearchEngine, suggestion);
    95                 }
    96             }
    97         };
    99         mLongClickListener = new OnLongClickListener() {
   100             @Override
   101             public boolean onLongClick(View v) {
   102                 if (mEditSuggestionListener != null) {
   103                     final String suggestion = getSuggestionTextFromView(v);
   104                     mEditSuggestionListener.onEditSuggestion(suggestion);
   105                     return true;
   106                 }
   108                 return false;
   109             }
   110         };
   112         mInflater = LayoutInflater.from(context);
   113         mInflater.inflate(R.layout.search_engine_row, this);
   115         mSuggestionView = (FlowLayout) findViewById(R.id.suggestion_layout);
   116         mIconView = (FaviconView) findViewById(R.id.suggestion_icon);
   118         // User-entered search term is first suggestion
   119         mUserEnteredView = (LinearLayout) findViewById(R.id.suggestion_user_entered);
   120         mUserEnteredView.setOnClickListener(mClickListener);
   122         mUserEnteredTextView = (TextView) findViewById(R.id.suggestion_text);
   123     }
   125     private void setDescriptionOnSuggestion(View v, String suggestion) {
   126         v.setContentDescription(getResources().getString(R.string.suggestion_for_engine,
   127                                                          mSearchEngine.name, suggestion));
   128     }
   130     private String getSuggestionTextFromView(View v) {
   131         final TextView suggestionText = (TextView) v.findViewById(R.id.suggestion_text);
   132         return suggestionText.getText().toString();
   133     }
   135     private void setSuggestionOnView(View v, String suggestion) {
   136         final TextView suggestionText = (TextView) v.findViewById(R.id.suggestion_text);
   137         suggestionText.setText(suggestion);
   138         setDescriptionOnSuggestion(suggestionText, suggestion);
   139     }
   141     /**
   142      * Perform a search for the user-entered term.
   143      */
   144     public void performUserEnteredSearch() {
   145         String searchTerm = getSuggestionTextFromView(mUserEnteredView);
   146         if (mSearchListener != null) {
   147             Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "user");
   148             mSearchListener.onSearch(mSearchEngine, searchTerm);
   149         }
   150     }
   152     public void setSearchTerm(String searchTerm) {
   153         mUserEnteredTextView.setText(searchTerm);
   155         // mSearchEngine is not set in the first call to this method; the content description
   156         // is instead initially set in updateFromSearchEngine.
   157         if (mSearchEngine != null) {
   158             setDescriptionOnSuggestion(mUserEnteredTextView, searchTerm);
   159         }
   160     }
   162     public void setOnUrlOpenListener(OnUrlOpenListener listener) {
   163         mUrlOpenListener = listener;
   164     }
   166     public void setOnSearchListener(OnSearchListener listener) {
   167         mSearchListener = listener;
   168     }
   170     public void setOnEditSuggestionListener(OnEditSuggestionListener listener) {
   171         mEditSuggestionListener = listener;
   172     }
   174     public void updateFromSearchEngine(SearchEngine searchEngine, boolean animate) {
   175         // Update search engine reference.
   176         mSearchEngine = searchEngine;
   178         // Set the search engine icon (e.g., Google) for the row.
   179         mIconView.updateAndScaleImage(mSearchEngine.getIcon(), mSearchEngine.getEngineIdentifier());
   181         // Set the initial content description.
   182         setDescriptionOnSuggestion(mUserEnteredTextView, mUserEnteredTextView.getText().toString());
   184         // Add additional suggestions given by this engine.
   185         final int recycledSuggestionCount = mSuggestionView.getChildCount();
   187         int suggestionCounter = 0;
   188         for (String suggestion : mSearchEngine.getSuggestions()) {
   189             final View suggestionItem;
   191             // Reuse suggestion views from recycled view, if possible.
   192             if (suggestionCounter + 1 < recycledSuggestionCount) {
   193                 suggestionItem = mSuggestionView.getChildAt(suggestionCounter + 1);
   194                 suggestionItem.setVisibility(View.VISIBLE);
   195             } else {
   196                 suggestionItem = mInflater.inflate(R.layout.suggestion_item, null);
   198                 suggestionItem.setOnClickListener(mClickListener);
   199                 suggestionItem.setOnLongClickListener(mLongClickListener);
   201                 final ImageView magnifier =
   202                         (ImageView) suggestionItem.findViewById(R.id.suggestion_magnifier);
   203                 magnifier.setVisibility(View.GONE);
   205                 mSuggestionView.addView(suggestionItem);
   206             }
   208             setSuggestionOnView(suggestionItem, suggestion);
   210             if (animate) {
   211                 AlphaAnimation anim = new AlphaAnimation(0, 1);
   212                 anim.setDuration(ANIMATION_DURATION);
   213                 anim.setStartOffset(suggestionCounter * ANIMATION_DURATION);
   214                 suggestionItem.startAnimation(anim);
   215             }
   217             ++suggestionCounter;
   218         }
   220         // Hide extra suggestions that have been recycled.
   221         for (int i = suggestionCounter + 1; i < recycledSuggestionCount; ++i) {
   222             mSuggestionView.getChildAt(i).setVisibility(View.GONE);
   223         }
   225         // Make sure mSelectedView is still valid.
   226         if (mSelectedView >= mSuggestionView.getChildCount()) {
   227             mSelectedView = mSuggestionView.getChildCount() - 1;
   228         }
   229     }
   231     @Override
   232     public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
   233         final View suggestion = mSuggestionView.getChildAt(mSelectedView);
   235         if (event.getAction() != android.view.KeyEvent.ACTION_DOWN) {
   236             return false;
   237         }
   239         switch (event.getKeyCode()) {
   240         case KeyEvent.KEYCODE_DPAD_RIGHT:
   241             final View nextSuggestion = mSuggestionView.getChildAt(mSelectedView + 1);
   242             if (nextSuggestion != null) {
   243                 changeSelectedSuggestion(suggestion, nextSuggestion);
   244                 mSelectedView++;
   245                 return true;
   246             }
   247             break;
   249         case KeyEvent.KEYCODE_DPAD_LEFT:
   250             final View prevSuggestion = mSuggestionView.getChildAt(mSelectedView - 1);
   251             if (prevSuggestion != null) {
   252                 changeSelectedSuggestion(suggestion, prevSuggestion);
   253                 mSelectedView--;
   254                 return true;
   255             }
   256             break;
   258         case KeyEvent.KEYCODE_BUTTON_A:
   259             // TODO: handle long pressing for editing suggestions
   260             return suggestion.performClick();
   261         }
   263         return false;
   264     }
   266     private void changeSelectedSuggestion(View oldSuggestion, View newSuggestion) {
   267         oldSuggestion.setDuplicateParentStateEnabled(false);
   268         newSuggestion.setDuplicateParentStateEnabled(true);
   269         oldSuggestion.refreshDrawableState();
   270         newSuggestion.refreshDrawableState();
   271     }
   273     public void onSelected() {
   274         mSelectedView = 0;
   275         mUserEnteredView.setDuplicateParentStateEnabled(true);
   276         mUserEnteredView.refreshDrawableState();
   277     }
   279     public void onDeselected() {
   280         final View suggestion = mSuggestionView.getChildAt(mSelectedView);
   281         suggestion.setDuplicateParentStateEnabled(false);
   282         suggestion.refreshDrawableState();
   283     }
   284 }

mercurial