content: package com.lapism.searchview.view;
  
  import android.annotation.TargetApi;
  import android.app.Activity;
  import android.app.Fragment;
  import android.content.Context;
  import android.content.Intent;
  import android.content.pm.PackageManager;
  import android.content.pm.ResolveInfo;
  import android.content.res.TypedArray;
  import android.os.Build;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.speech.RecognizerIntent;
  import androidx.annotation.StringRes;
  import androidx.cardview.widget.CardView;
  import androidx.core.content.ContextCompat;
  import androidx.recyclerview.widget.DefaultItemAnimator;
  import androidx.recyclerview.widget.LinearLayoutManager;
  import androidx.recyclerview.widget.RecyclerView;
  
  import android.text.Editable;
  import android.text.TextUtils;
  import android.text.TextWatcher;
  import android.util.AttributeSet;
  import android.util.TypedValue;
  import android.view.KeyEvent;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewTreeObserver;
  import android.view.inputmethod.InputMethodManager;
  import android.widget.EditText;
  import android.widget.Filter;
  import android.widget.FrameLayout;
  import android.widget.ImageView;
  import android.widget.TextView;
  
  import com.lapism.arrow.ArrowDrawable;
  import com.lapism.searchview.R;
  import com.lapism.searchview.adapter.SearchAdapter;
  
  import java.util.List;
  
  // TODO
  // clean code this
  // Voice PERMISSION
  // FIX EDIT TEXT PROPERTIES
  // fix out animation
  // CoordinatorLayout.Behavior
  // database inside SearchView
  // animace out, krizek, animace otevirani, zavirani toho okna, dabazi dovnitr
  // zadne suggestions
  
  public class SearchView extends FrameLayout implements Filter.FilterListener, View.OnClickListener {
  
      public static final int SPEECH_REQUEST_CODE = 1234;
      private final Context mContext;
      private int mVersion = SearchCodes.VERSION_TOOLBAR;
      private int mStyle = SearchCodes.STYLE_TOOLBAR_CLASSIC;
      private int ANIMATION_DURATION = 360;
      private boolean mVoice = true;
      private boolean mIsSearchOpen = false;
      private float mIsSearchArrowHamburgerState = ArrowDrawable.STATE_HAMBURGER;
      private String VOICE_SEARCH_TEXT = "Speak now";
      private View mDivider;
      private View mShadow;
      private Activity mActivity = null;
      private Fragment mFragment = null;
      private SearchAdapter mSearchAdapter;
      private CharSequence mOldQueryText;
      private ArrowDrawable mSearchArrow;
      private RecyclerView mRecyclerView;
      private CardView mCardView;
      private EditText mEditText;
      private ImageView mBackImageView;
      private ImageView mVoiceImageView;
      private ImageView mEmptyImageView;
      private OnQueryTextListener mOnQueryChangeListener;
      private SearchViewListener mSearchViewListener;
      private SearchMenuListener mSearchMenuListener;
      private CharSequence mUserQuery;
      private SavedState mSavedState;
  
      public SearchView(Context context) {
          this(context, null);
      }
  
      public SearchView(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public SearchView(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          mContext = context; // getContext();
          initView();
          initStyle(attrs, defStyleAttr, 0);
      }
  
      @TargetApi(Build.VERSION_CODES.LOLLIPOP)
      public SearchView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
          mContext = context;
          initView();
          initStyle(attrs, defStyleAttr, defStyleRes);
      }
  
      // init ----------------------------------------------------------------------------------------
      private void initView() {
          LayoutInflater.from(mContext).inflate((R.layout.search_view), this, true);
  
          mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView_result);
          mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
          mRecyclerView.setHasFixedSize(true);
          mRecyclerView.setItemAnimator(new DefaultItemAnimator());
  
          mBackImageView = (ImageView) findViewById(R.id.imageView_arrow_back);
          mBackImageView.setOnClickListener(this);
  
          mVoiceImageView = (ImageView) findViewById(R.id.imageView_mic);
          mVoiceImageView.setOnClickListener(this);
  
          mEmptyImageView = (ImageView) findViewById(R.id.imageView_clear);
          mEmptyImageView.setOnClickListener(this);
          mEmptyImageView.setVisibility(View.GONE);
  
          mShadow = findViewById(R.id.view_shadow);
          mShadow.setOnClickListener(this);
          mShadow.setVisibility(View.GONE);
  
          mDivider = findViewById(R.id.view_divider);
          mDivider.setVisibility(View.GONE);
  
          mCardView = (CardView) findViewById(R.id.cardView);
  
          mEditText = (EditText) findViewById(R.id.editText_input);
          mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
              @Override
              public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                  onSubmitQuery();
                  return true;
              }
          });
          mEditText.addTextChangedListener(new TextWatcher() {
              @Override
              public void beforeTextChanged(CharSequence s, int start, int count, int after) {
              }
  
              @Override
              public void onTextChanged(CharSequence s, int start, int before, int count) {
                  mUserQuery = s;
                  startFilter(s);
                  SearchView.this.onTextChanged(s);
              }
  
              @Override
              public void afterTextChanged(Editable s) {
              }
          });
          mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
              @Override
              public void onFocusChange(View v, boolean hasFocus) {
                  if (hasFocus) {
                      in();
                  } else {
                      out();
                  }
              }
          });
      }
  
      private void initStyle(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          TypedArray attr = mContext.obtainStyledAttributes(attrs, R.styleable.SearchView, defStyleAttr, defStyleRes);
          if (attr != null) {
              if (attr.hasValue(R.styleable.SearchView_search_version)) {
                  setVersion(attr.getInt(R.styleable.SearchView_search_version, SearchCodes.VERSION_TOOLBAR));
              }
              if (attr.hasValue(R.styleable.SearchView_search_style)) {
                  setStyle(attr.getInt(R.styleable.SearchView_search_style, SearchCodes.STYLE_TOOLBAR_CLASSIC));
              }
              if (attr.hasValue(R.styleable.SearchView_search_theme)) {
                  setTheme(attr.getInt(R.styleable.SearchView_search_theme, SearchCodes.THEME_LIGHT));
              }
              if (attr.hasValue(R.styleable.SearchView_search_divider)) {
                  setDivider(attr.getBoolean(R.styleable.SearchView_search_divider, false));
              }
              if (attr.hasValue(R.styleable.SearchView_search_hint)) {
                  setHint(attr.getString(R.styleable.SearchView_search_hint));
              }
              if (attr.hasValue(R.styleable.SearchView_search_hint_size)) {
                  setHintSize(attr.getDimensionPixelSize(R.styleable.SearchView_search_hint_size, 0));
              }
              if (attr.hasValue(R.styleable.SearchView_search_voice)) {
                  setVoice(attr.getBoolean(R.styleable.SearchView_search_voice, false));
              }
              if (attr.hasValue(R.styleable.SearchView_search_voice_text)) {
                  setVoiceText(attr.getString(R.styleable.SearchView_search_voice_text));
              }
              if (attr.hasValue(R.styleable.SearchView_search_animation_duration)) {
                  setAnimationDuration(attr.getInt(R.styleable.SearchView_search_animation_duration, ANIMATION_DURATION));
              }
              if (attr.hasValue(R.styleable.SearchView_search_shadow_color)) {
                  setShadowColor(attr.getColor(R.styleable.SearchView_search_shadow_color, 0));
              }
              attr.recycle();
          }
      }
  
      // parameters ----------------------------------------------------------------------------------
      public void setVersion(int version) {
          mVersion = version;
  
          CardView.LayoutParams params = new CardView.LayoutParams(
                  CardView.LayoutParams.MATCH_PARENT,
                  CardView.LayoutParams.WRAP_CONTENT
          );
  
          if (mVersion == SearchCodes.VERSION_TOOLBAR) {
              mIsSearchOpen = true;
              mEditText.clearFocus();
  
              int top = mContext.getResources().getDimensionPixelSize(R.dimen.search_toolbar_margin_top);
              int leftStart = mContext.getResources().getDimensionPixelSize(R.dimen.search_toolbar_margin_left);
              int rightEnd = mContext.getResources().getDimensionPixelSize(R.dimen.search_toolbar_margin_right);
              int bottom = 0;
  
              params.setMargins(leftStart, top, rightEnd, bottom);
          }
  
          if (mVersion == SearchCodes.VERSION_MENU_ITEM) {
              setVisibility(View.GONE);
  
              int top = mContext.getResources().getDimensionPixelSize(R.dimen.search_menu_item_margin_top);
              int leftStart = mContext.getResources().getDimensionPixelSize(R.dimen.search_menu_item_margin_left);
              int rightEnd = mContext.getResources().getDimensionPixelSize(R.dimen.search_menu_item_margin_right);
              int bottom = mContext.getResources().getDimensionPixelSize(R.dimen.search_menu_item_margin_bottom);
  
              params.setMargins(leftStart, top, rightEnd, bottom);
          }
  
          mCardView.setLayoutParams(params);
      }
  
      public void setStyle(int style) {
          if (mVersion == SearchCodes.VERSION_TOOLBAR) {
              if (style == SearchCodes.STYLE_TOOLBAR_CLASSIC) {
                  mSearchArrow = new ArrowDrawable(mContext);
                  mBackImageView.setImageDrawable(mSearchArrow);
                  mVoiceImageView.setImageResource(R.drawable.search_ic_mic_black_24dp);
                  mEmptyImageView.setImageResource(R.drawable.search_ic_clear_black_24dp);
              }
          }
          if (mVersion == SearchCodes.VERSION_MENU_ITEM) {
              if (style == SearchCodes.STYLE_MENU_ITEM_CLASSIC) {
                  mBackImageView.setImageResource(R.drawable.search_ic_arrow_back_black_24dp);
                  mVoiceImageView.setImageResource(R.drawable.search_ic_mic_black_24dp);
                  mEmptyImageView.setImageResource(R.drawable.search_ic_clear_black_24dp);
              }
              if (style == SearchCodes.STYLE_MENU_ITEM_COLOR) {
                  mBackImageView.setImageResource(R.drawable.search_ic_arrow_back_color_24dp);
                  mVoiceImageView.setImageResource(R.drawable.search_ic_mic_color_24dp);
                  mEmptyImageView.setImageResource(R.drawable.search_ic_clear_color_24dp);
              }
          }
          mStyle = style;
      }
  
      public void setTheme(int theme) {
          if (theme == SearchCodes.THEME_LIGHT) {
              if (mVersion == SearchCodes.VERSION_TOOLBAR) {
                  mSearchArrow.setColor(ContextCompat.getColor(mContext, R.color.search_light_icon));
                  mVoiceImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_light_icon));
                  mEmptyImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_light_icon));
              }
              if (mVersion == SearchCodes.VERSION_MENU_ITEM) {
                  if (mStyle == SearchCodes.STYLE_MENU_ITEM_CLASSIC) {
                      mBackImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_light_icon));
                      mVoiceImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_light_icon));
                      mEmptyImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_light_icon));
                  }
              }
              mRecyclerView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.search_light_background));
              mCardView.setCardBackgroundColor(ContextCompat.getColor(mContext, R.color.search_light_background));
              mEditText.setTextColor(ContextCompat.getColor(mContext, R.color.search_light_text));
              mEditText.setHintTextColor(ContextCompat.getColor(mContext, R.color.search_light_text_hint));
          }
  
          if (theme == SearchCodes.THEME_DARK) {
              if (mVersion == SearchCodes.VERSION_TOOLBAR) {
                  mSearchArrow.setColor(ContextCompat.getColor(mContext, R.color.search_dark_icon));
                  mVoiceImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_dark_icon));
                  mEmptyImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_dark_icon));
              }
              if (mVersion == SearchCodes.VERSION_MENU_ITEM) {
                  if (mStyle == SearchCodes.STYLE_MENU_ITEM_CLASSIC) {
                      mBackImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_dark_icon));
                      mVoiceImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_dark_icon));
                      mEmptyImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.search_dark_icon));
                  }
              }
              mRecyclerView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.search_dark_background));
              mCardView.setCardBackgroundColor(ContextCompat.getColor(mContext, R.color.search_dark_background));
              mEditText.setTextColor(ContextCompat.getColor(mContext, R.color.search_dark_text));
              mEditText.setHintTextColor(ContextCompat.getColor(mContext, R.color.search_dark_text_hint));
          }
      }
  
      public void setDivider(boolean divider) {
          if (divider) {
              mRecyclerView.addItemDecoration(new SearchDivider(mContext));
          } else {
              mRecyclerView.removeItemDecoration(new SearchDivider(mContext));
          }
      }
  
      public void setHint(CharSequence hint) {
          mEditText.setHint(hint);
      }
  
      public void setHint(@StringRes int hint) {
          mEditText.setHint(hint);
      }
  
      public void setHintSize(float size) {
          mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
      }
  
      public void setVoice(boolean voice) {
          mVoice = voice;
          if (voice && isVoiceAvailable()) {
              mVoiceImageView.setVisibility(View.VISIBLE);
          } else {
              mVoiceImageView.setVisibility(View.GONE);
          }
      }
  
      public void setVoice(boolean voice, Activity context) {
          mActivity = context;
          setVoice(voice);
      }
  
      public void setVoice(boolean voice, Fragment context) {
          mFragment = context;
          setVoice(voice);
      }
  
      public void setVoiceText(String voice_text) {
          VOICE_SEARCH_TEXT = voice_text;
      }
  
      public void setAnimationDuration(int animation_duration) {
          ANIMATION_DURATION = animation_duration;
      }
  
      public void setShadowColor(int color) {
          mShadow.setBackgroundColor(color);
      }
  
      // public --------------------------------------------------------------------------------------
      public void show(boolean animate) {
          setVisibility(View.VISIBLE);
  
          mEditText.requestFocus();
          mEditText.setText(null);
  
          mIsSearchOpen = true;
  
          if (mVersion == SearchCodes.VERSION_MENU_ITEM) {
              if (animate) {
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                      revealInAnimation();
                  } else {
                      SearchAnimator.fadeInAnimation(mCardView, ANIMATION_DURATION);
                  }
              } else {
                  mCardView.setVisibility(View.VISIBLE);
              }
              if (mSearchViewListener != null) {
                  mSearchViewListener.onSearchViewShown();
              }
          }
      }
  
      public void hide(boolean animate) {
          mEditText.clearFocus();
          mEditText.setText(null);
  
          mIsSearchOpen = false;
  
          if (mVersion == SearchCodes.VERSION_MENU_ITEM) {
              if (animate) {
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                      SearchAnimator.revealOutAnimation(mContext, mCardView, ANIMATION_DURATION);
                  } else {
                      SearchAnimator.fadeOutAnimation(mCardView, ANIMATION_DURATION);
                  }
                  postDelayed(new Runnable() {
                      @Override
                      public void run() {
                          setVisibility(View.GONE);
                          if (mSearchViewListener != null) {
                              mSearchViewListener.onSearchViewClosed();
                          }
                      }
                  }, ANIMATION_DURATION);
              } else {
                  setVisibility(View.GONE);
                  if (mSearchViewListener != null) {
                      mSearchViewListener.onSearchViewClosed();
                  }
              }
          }
      }
  
      public boolean isSearchOpen() {
          return mIsSearchOpen;
      }
  
      public void setQuery(CharSequence query) {
          mEditText.setText(query);
          if (query != null) {
              mEditText.setSelection(mEditText.length());
              mUserQuery = query;
          }
          if (!TextUtils.isEmpty(query)) {
              onSubmitQuery();
          }
      }
  
      public void setAdapter(SearchAdapter adapter) {
          mSearchAdapter = adapter;
          mRecyclerView.setAdapter(adapter);
          startFilter(mEditText.getText());
      }
  
      // private -------------------------------------------------------------------------------------
      @TargetApi(Build.VERSION_CODES.LOLLIPOP)
      private void revealInAnimation() {
          mCardView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
              @Override
              public void onGlobalLayout() {
                  mCardView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                  SearchAnimator.revealInAnimation(mContext, mCardView, ANIMATION_DURATION);
              }
          });
      }
  
      private void showSuggestions() {
          if (mSearchAdapter != null && mSearchAdapter.getItemCount() > 0 && mRecyclerView.getVisibility() == View.GONE) {
              mDivider.setVisibility(View.VISIBLE);
              mRecyclerView.setVisibility(View.VISIBLE);
              mRecyclerView.setAlpha(0.0f);
              mRecyclerView.animate().alpha(1.0f);
          }
      }
  
      private void hideSuggestions() {
          if (mRecyclerView.getVisibility() == View.VISIBLE) {
              mRecyclerView.setVisibility(View.GONE);
              mDivider.setVisibility(View.GONE);
          }
      }
  
      private void in() {
          showKeyboard();
          showSuggestions();
          mShadow.setVisibility(View.VISIBLE);
          if (mSearchArrow != null && mVersion == SearchCodes.VERSION_TOOLBAR) {
              mSearchArrow.setVerticalMirror(false);
              mSearchArrow.animate(ArrowDrawable.STATE_ARROW);
              mIsSearchArrowHamburgerState = ArrowDrawable.STATE_ARROW;
          }
      }
  
      public void out() {
          hideKeyboard();
          hideSuggestions();
          mShadow.setVisibility(View.GONE);
          if (mSearchArrow != null && mVersion == SearchCodes.VERSION_TOOLBAR) {
              mSearchArrow.setVerticalMirror(true);
              mSearchArrow.animate(ArrowDrawable.STATE_HAMBURGER);
              mIsSearchArrowHamburgerState = ArrowDrawable.STATE_HAMBURGER;
          }
      }
  
      private void showKeyboard() {
          InputMethodManager imm = (InputMethodManager) mEditText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
          imm.showSoftInput(mEditText, 0);
      }
  
      private void hideKeyboard() {
          InputMethodManager imm = (InputMethodManager) mEditText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
          imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
      }
  
      private boolean isVoiceAvailable() {
          PackageManager pm = getContext().getPackageManager();
          List<ResolveInfo> activities = pm.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
          return activities.size() != 0;
      }
  
      private void onVoiceClicked() {
          Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
          intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
          intent.putExtra(RecognizerIntent.EXTRA_PROMPT, VOICE_SEARCH_TEXT);
          intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
  
          if (mActivity != null) {
              mActivity.startActivityForResult(intent, SPEECH_REQUEST_CODE);
          } else if (mFragment != null) {
              mFragment.startActivityForResult(intent, SPEECH_REQUEST_CODE);
          } else {
              if (mContext instanceof Activity) {
                  ((Activity) mContext).startActivityForResult(intent, SPEECH_REQUEST_CODE);
              }
          }
      }
  
      private void onSubmitQuery() {
          CharSequence query = mEditText.getText();
          if (query != null && TextUtils.getTrimmedLength(query) > 0) {
              if (mOnQueryChangeListener == null || !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
                  mEditText.setText(null);
              }
          }
      }
  
      private void startFilter(CharSequence s) {
          if (mSearchAdapter != null) {
              (mSearchAdapter).getFilter().filter(s, this);
          }
      }
  
      private void checkVoiceStatus(boolean status) {
          if (mVoice && status && isVoiceAvailable()) {
              mVoiceImageView.setVisibility(View.VISIBLE);
          } else {
              mVoiceImageView.setVisibility(View.GONE);
          }
      }
  
      private void onTextChanged(CharSequence newText) {
          CharSequence text = mEditText.getText();
          mUserQuery = text;
          boolean hasText = !TextUtils.isEmpty(text);
  
          if (hasText) {
              mEmptyImageView.setVisibility(View.VISIBLE);
              checkVoiceStatus(false);
          } else {
              mEmptyImageView.setVisibility(View.GONE);
              checkVoiceStatus(true);
          }
  
          if (mOnQueryChangeListener != null && !TextUtils.equals(newText, mOldQueryText)) {
              mOnQueryChangeListener.onQueryTextChange(newText.toString());
          }
          mOldQueryText = newText.toString();
      }
  
      // interfaces ----------------------------------------------------------------------------------
      public void setOnQueryTextListener(OnQueryTextListener listener) {
          mOnQueryChangeListener = listener;
      }
  
      public void setOnSearchViewListener(SearchViewListener listener) {
          mSearchViewListener = listener;
      }
  
      public void setOnSearchMenuListener(SearchMenuListener listener) {
          mSearchMenuListener = listener;
      }
  
      // implements ----------------------------------------------------------------------------------
      @Override
      public void onFilterComplete(int text) {
          if (text > 0) {
              showSuggestions();
          } else {
              hideSuggestions();
          }
      }
  
      @Override
      public void onClick(View v) {
          if (v == mBackImageView || v == mShadow) {
  
              if (mVersion == SearchCodes.VERSION_TOOLBAR) {
                  if (mIsSearchArrowHamburgerState == ArrowDrawable.STATE_HAMBURGER) {
                      mSearchMenuListener.onMenuClick();
                  } else {
                      hide(false);
                  }
              }
  
              if (mVersion == SearchCodes.VERSION_MENU_ITEM) {
                  hide(true);
              }
          }
  
          if (v == mVoiceImageView) {
              onVoiceClicked();
          }
  
          if (v == mEmptyImageView) {
              mEditText.setText(null);
          }
      }
  
      // ---------------------------------------------------------------------------------------------
      @Override
      public Parcelable onSaveInstanceState() {
          Parcelable superState = super.onSaveInstanceState();
          mSavedState = new SavedState(superState);
          mSavedState.query = mUserQuery != null ? mUserQuery.toString() : null;
          mSavedState.isSearchOpen = mIsSearchOpen;
          return mSavedState;
      }
  
      // TODO http://onegullibull.com/WP-OneGulliBull/?p=252
      @Override
      public void onRestoreInstanceState(Parcelable state) {
          if (!(state instanceof SavedState)) {
              super.onRestoreInstanceState(state);
              return;
          }
          mSavedState = (SavedState) state;
          if (mSavedState.isSearchOpen) {
              show(true);
              setQuery(mSavedState.query);
          }
          super.onRestoreInstanceState(mSavedState.getSuperState());
      }
  
      public interface OnQueryTextListener {
          boolean onQueryTextSubmit(String query);
  
          boolean onQueryTextChange(String newText);
      }
  
      public interface SearchViewListener {
          void onSearchViewShown();
  
          void onSearchViewClosed();
      }
  
      public interface SearchMenuListener {
          void onMenuClick();
      }
  
      // class ---------------------------------------------------------------------------------------
      private static class SavedState extends View.BaseSavedState {
          // TODO EDIT TEXT FOCUS ON ROTATION
          public static final Creator<SavedState> CREATOR =
                  new Creator<SavedState>() {
                      @Override
                      public SavedState createFromParcel(Parcel in) {
                          return new SavedState(in);
                      }
  
                      @Override
                      public SavedState[] newArray(int size) {
                          return new SavedState[size];
                      }
                  };
  
          String query;
          boolean isSearchOpen;
  
          public SavedState(Parcelable superState) {
              super(superState);
          }
  
          private SavedState(Parcel in) {
              super(in);
              this.query = in.readString();
              this.isSearchOpen = in.readInt() == 1;
          }
  
          @Override
          public void writeToParcel(Parcel out, int flags) {
              super.writeToParcel(out, flags);
              out.writeString(query);
              out.writeInt(isSearchOpen ? 1 : 0);
          }
  
      }
  
  }