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 file, 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 package org.mozilla.gecko.home; 7 8 import android.content.Context; 9 import android.content.Intent; 10 import android.graphics.Canvas; 11 import android.graphics.Paint; 12 import android.support.v4.content.ContextCompat; 13 import android.support.v7.widget.LinearLayoutManager; 14 import android.support.v7.widget.RecyclerView; 15 import android.util.AttributeSet; 16 import android.util.DisplayMetrics; 17 import android.util.TypedValue; 18 import android.view.View; 19 20 import org.mozilla.gecko.annotation.RobocopTarget; 21 import org.mozilla.gecko.R; 22 import org.mozilla.gecko.Telemetry; 23 import org.mozilla.gecko.TelemetryContract; 24 import org.mozilla.gecko.preferences.GeckoPreferences; 25 import org.mozilla.gecko.widget.RecyclerViewClickSupport; 26 27 import java.util.List; 28 29 public class SearchEngineBar extends RecyclerView 30 implements RecyclerViewClickSupport.OnItemClickListener { 31 private static final String LOGTAG = SearchEngineBar.class.getSimpleName(); 32 33 private static final float ICON_CONTAINER_MIN_WIDTH_DP = 72; 34 private static final float LABEL_CONTAINER_WIDTH_DP = 48; 35 36 public interface OnSearchBarClickListener { onSearchBarClickListener(SearchEngine searchEngine)37 void onSearchBarClickListener(SearchEngine searchEngine); 38 } 39 40 private final SearchEngineAdapter mAdapter; 41 private final LinearLayoutManager mLayoutManager; 42 private final Paint mDividerPaint; 43 private final float mMinIconContainerWidth; 44 private final float mDividerHeight; 45 private final int mLabelContainerWidth; 46 47 private int mIconContainerWidth; 48 private OnSearchBarClickListener mOnSearchBarClickListener; 49 SearchEngineBar(final Context context, final AttributeSet attrs)50 public SearchEngineBar(final Context context, final AttributeSet attrs) { 51 super(context, attrs); 52 53 mDividerPaint = new Paint(); 54 mDividerPaint.setColor(ContextCompat.getColor(context, R.color.toolbar_divider_grey)); 55 mDividerPaint.setStyle(Paint.Style.FILL_AND_STROKE); 56 57 final DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); 58 mMinIconContainerWidth = TypedValue.applyDimension( 59 TypedValue.COMPLEX_UNIT_DIP, ICON_CONTAINER_MIN_WIDTH_DP, displayMetrics); 60 mDividerHeight = context.getResources().getDimension(R.dimen.page_row_divider_height); 61 mLabelContainerWidth = Math.round(TypedValue.applyDimension( 62 TypedValue.COMPLEX_UNIT_DIP, LABEL_CONTAINER_WIDTH_DP, displayMetrics)); 63 64 mIconContainerWidth = Math.round(mMinIconContainerWidth); 65 66 mAdapter = new SearchEngineAdapter(context); 67 mAdapter.setIconContainerWidth(mIconContainerWidth); 68 mLayoutManager = new LinearLayoutManager(context); 69 mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); 70 71 setAdapter(mAdapter); 72 setLayoutManager(mLayoutManager); 73 74 RecyclerViewClickSupport.addTo(this) 75 .setOnItemClickListener(this); 76 } 77 setSearchEngines(List<SearchEngine> searchEngines)78 public void setSearchEngines(List<SearchEngine> searchEngines) { 79 mAdapter.setSearchEngines(searchEngines); 80 } 81 setOnSearchBarClickListener(OnSearchBarClickListener listener)82 public void setOnSearchBarClickListener(OnSearchBarClickListener listener) { 83 mOnSearchBarClickListener = listener; 84 } 85 86 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)87 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 88 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 89 90 final int searchEngineCount = mAdapter.getItemCount() - 1; 91 92 if (searchEngineCount > 0) { 93 final int availableWidth = getMeasuredWidth() - mLabelContainerWidth; 94 95 if (searchEngineCount * mMinIconContainerWidth <= availableWidth) { 96 // All search engines fit int: So let's just display all. 97 mIconContainerWidth = (int) mMinIconContainerWidth; 98 } else { 99 // If only (n) search engines fit into the available space then display only (x) 100 // search engines with (x) picked so that the last search engine will be cut-off 101 // (we only display half of it) to show the ability to scroll this view. 102 103 final double searchEnginesToDisplay = Math.floor((availableWidth / mMinIconContainerWidth) - 0.5) + 0.5; 104 // Use all available width and spread search engine icons 105 mIconContainerWidth = (int) (availableWidth / searchEnginesToDisplay); 106 } 107 108 mAdapter.setIconContainerWidth(mIconContainerWidth); 109 } 110 } 111 112 @Override onDraw(Canvas canvas)113 public void onDraw(Canvas canvas) { 114 super.onDraw(canvas); 115 116 canvas.drawRect(0, 0, getWidth(), mDividerHeight, mDividerPaint); 117 } 118 119 @Override onItemClicked(RecyclerView recyclerView, int position, View v)120 public void onItemClicked(RecyclerView recyclerView, int position, View v) { 121 if (mOnSearchBarClickListener == null) { 122 throw new IllegalStateException( 123 OnSearchBarClickListener.class.getSimpleName() + " is not initializer." 124 ); 125 } 126 127 if (position == 0) { 128 final Intent settingsIntent = new Intent(getContext(), GeckoPreferences.class); 129 GeckoPreferences.setResourceToOpen(settingsIntent, "preferences_search"); 130 getContext().startActivity(settingsIntent); 131 Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, "searchenginebar-settings"); 132 return; 133 } 134 135 final SearchEngine searchEngine = mAdapter.getItem(position); 136 mOnSearchBarClickListener.onSearchBarClickListener(searchEngine); 137 } 138 139 /** 140 * We manually add the override for getAdapter because we see this method getting stripped 141 * out during compile time by aggressive proguard rules. 142 */ 143 @RobocopTarget 144 @Override getAdapter()145 public SearchEngineAdapter getAdapter() { 146 return mAdapter; 147 } 148 } 149