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