MaterialSearchActionView.java revision 524ded5f9d27dda75c53d256922a39c867857575
1/*
2 * Copyright (C) 2014 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mail.ui;
19
20import android.content.Context;
21import android.content.res.Resources;
22import android.graphics.drawable.ColorDrawable;
23import android.graphics.drawable.Drawable;
24import android.support.annotation.DrawableRes;
25import android.text.Editable;
26import android.text.TextWatcher;
27import android.util.AttributeSet;
28import android.view.KeyEvent;
29import android.view.View;
30import android.view.ViewGroup;
31import android.view.inputmethod.EditorInfo;
32import android.view.inputmethod.InputMethodManager;
33import android.widget.EditText;
34import android.widget.ImageView;
35import android.widget.LinearLayout;
36import android.widget.TextView;
37
38import com.android.mail.R;
39import com.android.mail.utils.ViewUtils;
40
41/**
42 * Custom view for the action bar when search is displayed.
43 */
44public class MaterialSearchActionView extends LinearLayout implements TextWatcher,
45        View.OnClickListener, TextView.OnEditorActionListener, View.OnKeyListener {
46    private Drawable mNormalBackgroundDrawable;
47    private Drawable mTwoPaneLandConvModeBackgroundDrawable;
48    private @DrawableRes int mNormalBackButtonDrawable;
49    private @DrawableRes int mTwoPaneLandConvModeBackButtonDrawable;
50    private @DrawableRes int mNormalClearTextButtonDrawable;
51    private @DrawableRes int mTwoPaneLandConvModeClearTextButtonDrawable;
52    private @DrawableRes int mNormalVoiceButtonDrawable;
53    private @DrawableRes int mTwoPaneLandConvModeVoiceButtonDrawable;
54    private int mNormalTextColor;
55    private int mTwoPaneLandConvModeTextColor;
56
57    private MaterialSearchViewController mController;
58    private InputMethodManager mImm;
59    private boolean mShowingClose;
60    private boolean mSupportVoice;
61
62    private ImageView mBackButton;
63    private EditText mQueryText;
64    private ImageView mEndingButton;
65
66    public MaterialSearchActionView(Context context) {
67        this(context, null);
68    }
69
70    public MaterialSearchActionView(Context context, AttributeSet attrs) {
71        super(context, attrs);
72
73        final Resources res = getResources();
74        mNormalBackgroundDrawable = new ColorDrawable(res.getColor(android.R.color.white));
75        mTwoPaneLandConvModeBackgroundDrawable =
76                new ColorDrawable(res.getColor(R.color.actionbar_color));
77        mNormalBackButtonDrawable = R.drawable.ic_arrow_back_24dp_with_rtl;
78        mTwoPaneLandConvModeBackButtonDrawable = R.drawable.ic_arrow_back_wht_24dp;
79        mNormalClearTextButtonDrawable = R.drawable.ic_close_24dp;
80        mTwoPaneLandConvModeClearTextButtonDrawable = R.drawable.ic_close_wht_24dp;
81        mNormalVoiceButtonDrawable = R.drawable.ic_mic_24dp;
82        mTwoPaneLandConvModeVoiceButtonDrawable = R.drawable.ic_mic_white_24dp;
83        mNormalTextColor = res.getColor(R.color.search_query_text);
84        mTwoPaneLandConvModeTextColor = res.getColor(android.R.color.white);
85    }
86
87    // PUBLIC API
88    public void setController(MaterialSearchViewController controller, String initialQuery,
89            boolean supportVoice) {
90        mController = controller;
91        mQueryText.setText(initialQuery);
92        mSupportVoice = supportVoice;
93    }
94
95    public void clearSearchQuery() {
96        mQueryText.setText("");
97    }
98
99    public void focusSearchBar(boolean hasFocus) {
100        if (hasFocus) {
101            mQueryText.requestFocus();
102            mImm.showSoftInput(mQueryText, 0);
103        } else {
104            mImm.hideSoftInputFromWindow(mQueryText.getWindowToken(), 0);
105        }
106    }
107
108    public void adjustViewForTwoPaneLandscape(boolean alignWithTL, int xEnd) {
109        final ViewGroup.LayoutParams params = getLayoutParams();
110        if (alignWithTL) {
111            setBackgroundDrawable(mTwoPaneLandConvModeBackgroundDrawable);
112            mBackButton.setImageResource(mTwoPaneLandConvModeBackButtonDrawable);
113            if (mShowingClose) {
114                mEndingButton.setImageResource(mTwoPaneLandConvModeClearTextButtonDrawable);
115            } else {
116                mEndingButton.setImageResource(mTwoPaneLandConvModeVoiceButtonDrawable);
117            }
118            mQueryText.setTextColor(mTwoPaneLandConvModeTextColor);
119
120            if (ViewUtils.isViewRtl(this)) {
121                int[] coords = new int[2];
122                getLocationInWindow(coords);
123                params.width = coords[0] + getWidth() - xEnd;
124            } else {
125                params.width = xEnd;
126            }
127        } else {
128            setBackgroundDrawable(mNormalBackgroundDrawable);
129            mBackButton.setImageResource(mNormalBackButtonDrawable);
130            if (mShowingClose) {
131                mEndingButton.setImageResource(mNormalClearTextButtonDrawable);
132            } else {
133                mEndingButton.setImageResource(mNormalVoiceButtonDrawable);
134            }
135            mQueryText.setTextColor(mNormalTextColor);
136            params.width = ViewGroup.LayoutParams.MATCH_PARENT;
137        }
138        setLayoutParams(params);
139    }
140
141    @Override
142    protected void onFinishInflate() {
143        super.onFinishInflate();
144
145        mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
146        mBackButton = (ImageView) findViewById(R.id.search_actionbar_back_button);
147        mBackButton.setOnClickListener(this);
148        mQueryText = (EditText) findViewById(R.id.search_actionbar_query_text);
149        mQueryText.addTextChangedListener(this);
150        mQueryText.setOnClickListener(this);
151        mQueryText.setOnEditorActionListener(this);
152        mQueryText.setOnKeyListener(this);
153        mEndingButton = (ImageView) findViewById(R.id.search_actionbar_ending_button);
154        mEndingButton.setOnClickListener(this);
155        setupEndingButton(mQueryText.getText());
156    }
157
158    private void setupEndingButton(CharSequence currentText) {
159        final Resources res = getResources();
160        if (!mSupportVoice || currentText.length() > 0) {
161            mShowingClose = true;
162            mEndingButton.setImageResource(R.drawable.ic_close_24dp);
163            mEndingButton.setContentDescription(res.getString(R.string.search_clear_desc));
164        } else {
165            mShowingClose = false;
166            mEndingButton.setImageResource(R.drawable.ic_mic_24dp);
167            mEndingButton.setContentDescription(res.getString(R.string.search_voice_desc));
168        }
169    }
170
171    @Override
172    public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
173        // Only care about onTextChanged
174    }
175
176    @Override
177    public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
178        mController.onQueryTextChanged(charSequence.toString());
179        setupEndingButton(charSequence);
180    }
181
182    @Override
183    public void afterTextChanged(Editable editable) {
184        // Only care about onTextChanged
185    }
186
187    @Override
188    public void onClick(View view) {
189        if (view == mBackButton) {
190            mController.onSearchCanceled();
191            mQueryText.setText("");
192        } else if (view == mEndingButton) {
193            if (mShowingClose) {
194                mQueryText.setText("");
195                mController.showSearchActionBar(
196                        MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE);
197            } else {
198                mController.onVoiceSearch();
199            }
200        } else if (view == mQueryText) {
201            mController.showSearchActionBar(MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE);
202        }
203    }
204
205    @Override
206    public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
207        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
208            mController.onSearchPerformed(mQueryText.getText().toString());
209        }
210        return false;
211    }
212
213    @Override
214    public boolean onKey(View v, int keyCode, KeyEvent event) {
215        // Hardware keyboard doesn't represent Enter as Search through imeOptions, so we need to
216        // capture them manually here.
217        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_ENTER) {
218            mController.onSearchPerformed(mQueryText.getText().toString());
219        }
220        return false;
221    }
222}
223