com.tengio.FloatingSearchView.java Source code

Java tutorial

Introduction

Here is the source code for com.tengio.FloatingSearchView.java

Source

package com.tengio;

/**
 * Copyright (C) 2015 Ari C. <p></p> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at <p></p> http://www.apache.org/licenses/LICENSE-2.0 <p></p> Unless
 * required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.graphics.drawable.DrawerArrowDrawable;
import android.support.v7.view.menu.MenuBuilder;
import android.support.v7.widget.CardView;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.arlib.floatingsearchview.R;
import com.tengio.util.Util;
import com.tengio.util.adapter.TextWatcherAdapter;
import com.tengio.util.view.MenuView;
import com.tengio.util.view.SearchInputView;
import com.bartoszlipinski.viewpropertyobjectanimator.ViewPropertyObjectAnimator;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * A search UI widget that implements a floating search box also called persistent search.
 */
public class FloatingSearchView extends FrameLayout {

    private static final String TAG = "FloatingSearchView";

    private static final int CARD_VIEW_TOP_BOTTOM_SHADOW_HEIGHT = 3;
    private static final long CLEAR_BTN_FADE_ANIM_DURATION = 500;
    private static final int CLEAR_BTN_WIDTH = 48;
    private static final int LEFT_MENU_WIDTH_AND_MARGIN_START = 52;

    private final int BACKGROUND_DRAWABLE_ALPHA_SEARCH_FOCUSED = 150;
    private final int BACKGROUND_DRAWABLE_ALPHA_SEARCH_NOT_FOCUSED = 0;
    private final int BACKGROUND_FADE_ANIM_DURATION = 250;

    private final int MENU_ICON_ANIM_DURATION = 250;

    private final int ATTRS_SEARCH_BAR_MARGIN_DEFAULT = 0;

    public final static int LEFT_ACTION_MODE_SHOW_HAMBURGER = 1;
    public final static int LEFT_ACTION_MODE_SHOW_SEARCH = 2;
    public final static int LEFT_ACTION_MODE_SHOW_HOME = 3;
    public final static int LEFT_ACTION_MODE_NO_LEFT_ACTION = 4;
    private final static int LEFT_ACTION_MODE_NOT_SET = -1;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({ LEFT_ACTION_MODE_SHOW_HAMBURGER, LEFT_ACTION_MODE_SHOW_SEARCH, LEFT_ACTION_MODE_SHOW_HOME,
            LEFT_ACTION_MODE_NO_LEFT_ACTION, LEFT_ACTION_MODE_NOT_SET })
    public @interface LeftActionMode {

    }

    @LeftActionMode
    private final int ATTRS_SEARCH_BAR_LEFT_ACTION_MODE_DEFAULT = LEFT_ACTION_MODE_NO_LEFT_ACTION;
    private final boolean ATTRS_DISMISS_ON_OUTSIDE_TOUCH_DEFAULT = true;
    private final boolean ATTRS_DISMISS_ON_KEYBOARD_DISMISS_DEFAULT = false;
    private final boolean ATTRS_SEARCH_BAR_SHOW_SEARCH_KEY_DEFAULT = true;

    private Activity mHostActivity;

    private View mMainLayout;
    private boolean mDismissOnOutsideTouch = true;
    private boolean mIsFocused;
    private OnFocusChangeListener mFocusChangeListener;

    private CardView mQuerySection;
    private OnSearchListener mSearchListener;
    private SearchInputView mSearchInput;
    private boolean mCloseSearchOnSofteKeyboardDismiss;
    private String mTitleText;
    private boolean mIsTitleSet;
    private int mSearchInputTextColor = -1;
    private int mSearchInputHintColor = -1;
    private View mSearchInputParent;
    private String mOldQuery = "";
    private OnQueryChangeListener mQueryListener;
    private ImageView mLeftAction;
    private OnLeftMenuClickListener mOnMenuClickListener;
    private OnHomeActionClickListener mOnHomeActionClickListener;
    private ProgressBar mSearchProgress;
    private DrawerArrowDrawable mMenuBtnDrawable;
    private Drawable mIconBackArrow;
    private Drawable mIconSearch;
    @LeftActionMode
    int mLeftActionMode = LEFT_ACTION_MODE_NOT_SET;
    private int mLeftActionIconColor;
    private String mSearchHint;
    private boolean mShowSearchKey;
    private boolean mMenuOpen = false;
    private MenuView mMenuView;
    private int mMenuId = -1;
    private int mActionMenuItemColor;
    private int mOverflowIconColor;
    private OnMenuItemClickListener mActionMenuItemListener;
    private ImageView mClearButton;
    private int mClearBtnColor;
    private Drawable mIconClear;
    private int mBackgroundColor;
    private boolean mSkipQueryFocusChangeEvent;
    private boolean mSkipTextChangeEvent;

    private View mDivider;
    private int mDividerColor;

    private boolean mIsInitialLayout = true;

    /**
     * Interface for implementing a listener to listen to state changes in the query text.
     */
    public interface OnQueryChangeListener {

        /**
         * Called when the query has changed. It will be invoked when one or more characters in the query was changed.
         *
         * @param oldQuery the previous query
         * @param newQuery the new query
         */
        void onSearchTextChanged(String oldQuery, String newQuery);
    }

    /**
     * Interface for implementing a listener to listen to when the current search has completed.
     */
    public interface OnSearchListener {

        /**
         * Called when the current search has completed as a result of pressing search key in the keyboard. <p></p> Note: This will only get
         * called if {@link FloatingSearchView#setShowSearchKey(boolean)}} is set to true.
         *
         * @param currentQuery the text that is currently set in the query TextView
         */
        void onSearchAction(String currentQuery);
    }

    /**
     * Interface for implementing a callback to be invoked when the left menu (navigation menu) is clicked. <p></p> Note: This is only
     * relevant when leftActionMode is set to {@value #LEFT_ACTION_MODE_SHOW_HAMBURGER}
     */
    public interface OnLeftMenuClickListener {

        /**
         * Called when the menu button was clicked and the menu's state is now opened.
         */
        void onMenuOpened();

        /**
         * Called when the back button was clicked and the menu's state is now closed.
         */
        void onMenuClosed();
    }

    /**
     * Interface for implementing a callback to be invoked when the home action button (the back arrow) is clicked. <p></p> Note: This is
     * only relevant when leftActionMode is set to {@value #LEFT_ACTION_MODE_SHOW_HOME}
     */
    public interface OnHomeActionClickListener {

        /**
         * Called when the home button was clicked.
         */
        void onHomeClicked();
    }

    /**
     * Interface for implementing a listener to listen when an item in the action (the item can be presented as an action ,or as a menu item
     * in the overflow menu) menu has been selected.
     */
    public interface OnMenuItemClickListener {

        /**
         * Called when a menu item in has been selected.
         *
         * @param item the selected menu item.
         */
        void onActionMenuItemSelected(MenuItem item);
    }

    /**
     * Interface for implementing a listener to listen to for focus state changes.
     */
    public interface OnFocusChangeListener {

        /**
         * Called when the search bar has gained focus and listeners are now active.
         */
        void onFocus();

        /**
         * Called when the search bar has lost focus and listeners are no more active.
         */
        void onFocusCleared();
    }

    public FloatingSearchView(Context context) {
        this(context, null);
    }

    public FloatingSearchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    private void init(AttributeSet attrs) {

        mHostActivity = getHostActivity();

        mMainLayout = inflate(getContext(), R.layout.floating_search_layout, this);

        mQuerySection = (CardView) findViewById(R.id.search_query_section);
        mClearButton = (ImageView) findViewById(R.id.clear_btn);
        mSearchInput = (SearchInputView) findViewById(R.id.search_bar_text);
        mSearchInputParent = findViewById(R.id.search_input_parent);
        mLeftAction = (ImageView) findViewById(R.id.left_action);
        mSearchProgress = (ProgressBar) findViewById(R.id.search_bar_search_progress);
        initDrawables();
        mClearButton.setImageDrawable(mIconClear);
        mMenuView = (MenuView) findViewById(R.id.menu_view);

        mDivider = findViewById(R.id.divider);

        setupViews(attrs);
    }

    private Activity getHostActivity() {
        Context context = getContext();
        while (context instanceof ContextWrapper) {
            if (context instanceof Activity) {
                return (Activity) context;
            }
            context = ((ContextWrapper) context).getBaseContext();
        }
        return null;
    }

    private void initDrawables() {
        mMenuBtnDrawable = new DrawerArrowDrawable(getContext());
        mIconClear = Util.getWrappedDrawable(getContext(), R.drawable.ic_clear_black_24dp);
        mIconBackArrow = Util.getWrappedDrawable(getContext(), R.drawable.ic_arrow_back_black_24dp);
        mIconSearch = Util.getWrappedDrawable(getContext(), R.drawable.ic_search_black_24dp);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        if (mIsInitialLayout) {

            mIsInitialLayout = false;

            if (isInEditMode()) {
                inflateOverflowMenu(mMenuId);
            }
        }
    }

    private void setupViews(AttributeSet attrs) {

        if (attrs != null) {
            applyXmlAttributes(attrs);
        }

        setupQueryBar();
    }

    private void applyXmlAttributes(AttributeSet attrs) {

        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FloatingSearchView);

        try {

            int searchBarWidth = a.getDimensionPixelSize(
                    R.styleable.FloatingSearchView_floatingSearch_searchBarWidth,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            mQuerySection.getLayoutParams().width = searchBarWidth;
            mDivider.getLayoutParams().width = searchBarWidth;
            int searchBarLeftMargin = a.getDimensionPixelSize(
                    R.styleable.FloatingSearchView_floatingSearch_searchBarMarginLeft,
                    ATTRS_SEARCH_BAR_MARGIN_DEFAULT);
            int searchBarTopMargin = a.getDimensionPixelSize(
                    R.styleable.FloatingSearchView_floatingSearch_searchBarMarginTop,
                    ATTRS_SEARCH_BAR_MARGIN_DEFAULT);
            int searchBarRightMargin = a.getDimensionPixelSize(
                    R.styleable.FloatingSearchView_floatingSearch_searchBarMarginRight,
                    ATTRS_SEARCH_BAR_MARGIN_DEFAULT);
            LayoutParams querySectionLP = (LayoutParams) mQuerySection.getLayoutParams();
            LayoutParams dividerLP = (LayoutParams) mDivider.getLayoutParams();
            int cardPadding = Util.dpToPx(CARD_VIEW_TOP_BOTTOM_SHADOW_HEIGHT);
            querySectionLP.setMargins(searchBarLeftMargin, searchBarTopMargin, searchBarRightMargin, 0);
            dividerLP.setMargins(searchBarLeftMargin + cardPadding, 0, searchBarRightMargin + cardPadding,
                    ((MarginLayoutParams) mDivider.getLayoutParams()).bottomMargin);
            mQuerySection.setLayoutParams(querySectionLP);
            mDivider.setLayoutParams(dividerLP);

            setSearchHint(a.getString(R.styleable.FloatingSearchView_floatingSearch_searchHint));
            setShowSearchKey(a.getBoolean(R.styleable.FloatingSearchView_floatingSearch_showSearchKey,
                    ATTRS_SEARCH_BAR_SHOW_SEARCH_KEY_DEFAULT));
            setCloseSearchOnKeyboardDismiss(
                    a.getBoolean(R.styleable.FloatingSearchView_floatingSearch_close_search_on_keyboard_dismiss,
                            ATTRS_DISMISS_ON_KEYBOARD_DISMISS_DEFAULT));
            setDismissOnOutsideClick(
                    a.getBoolean(R.styleable.FloatingSearchView_floatingSearch_dismissOnOutsideTouch,
                            ATTRS_DISMISS_ON_OUTSIDE_TOUCH_DEFAULT));
            //noinspection ResourceType
            mLeftActionMode = a.getInt(R.styleable.FloatingSearchView_floatingSearch_leftActionMode,
                    ATTRS_SEARCH_BAR_LEFT_ACTION_MODE_DEFAULT);
            if (a.hasValue(R.styleable.FloatingSearchView_floatingSearch_menu)) {
                mMenuId = a.getResourceId(R.styleable.FloatingSearchView_floatingSearch_menu, -1);
            }
            setBackgroundColor(a.getColor(R.styleable.FloatingSearchView_floatingSearch_backgroundColor,
                    Util.getColor(getContext(), R.color.background)));
            setLeftActionIconColor(a.getColor(R.styleable.FloatingSearchView_floatingSearch_leftActionColor,
                    Util.getColor(getContext(), R.color.left_action_icon)));
            setActionMenuOverflowColor(
                    a.getColor(R.styleable.FloatingSearchView_floatingSearch_actionMenuOverflowColor,
                            Util.getColor(getContext(), R.color.overflow_icon_color)));
            setMenuItemIconColor(a.getColor(R.styleable.FloatingSearchView_floatingSearch_menuItemIconColor,
                    Util.getColor(getContext(), R.color.menu_icon_color)));
            setDividerColor(a.getColor(R.styleable.FloatingSearchView_floatingSearch_dividerColor,
                    Util.getColor(getContext(), R.color.divider)));
            setClearBtnColor(a.getColor(R.styleable.FloatingSearchView_floatingSearch_clearBtnColor,
                    Util.getColor(getContext(), R.color.clear_btn_color)));
            setViewTextColor(a.getColor(R.styleable.FloatingSearchView_floatingSearch_viewTextColor,
                    Util.getColor(getContext(), R.color.dark_gray)));
            setHintTextColor(a.getColor(R.styleable.FloatingSearchView_floatingSearch_hintTextColor,
                    Util.getColor(getContext(), R.color.hint_color)));
            setFont(a.getString(R.styleable.FloatingSearchView_floatingSearch_textFont));
        } finally {
            a.recycle();
        }
    }

    private void setupQueryBar() {

        mSearchInput.setTextColor(mSearchInputTextColor);
        mSearchInput.setHintTextColor(mSearchInputHintColor);

        if (!isInEditMode() && mHostActivity != null) {
            mHostActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
        }

        ViewTreeObserver vto = mQuerySection.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Util.removeGlobalLayoutObserver(mQuerySection, this);

                inflateOverflowMenu(mMenuId);
            }
        });

        mMenuView.setMenuCallback(new MenuBuilder.Callback() {
            @Override
            public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {

                if (mActionMenuItemListener != null) {
                    mActionMenuItemListener.onActionMenuItemSelected(item);
                }

                //todo check if we should care about this return or not
                return false;
            }

            @Override
            public void onMenuModeChange(MenuBuilder menu) {
            }
        });

        mMenuView.setOnVisibleWidthChanged(new MenuView.OnVisibleWidthChangedListener() {
            @Override
            public void onItemsMenuVisibleWidthChanged(int newVisibleWidth) {

                refreshSearchInputPaddingEnd(newVisibleWidth);
            }
        });

        mMenuView.setActionIconColor(mActionMenuItemColor);
        mMenuView.setOverflowColor(mOverflowIconColor);

        mClearButton.setVisibility(View.INVISIBLE);
        mClearButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mSearchInput.setText("");
            }
        });

        mSearchInput.addTextChangedListener(new TextWatcherAdapter() {

            public void onTextChanged(final CharSequence s, int start, int before, int count) {
                //todo investigate why this is called twice when pressing back on the keyboard

                if (mSkipTextChangeEvent || !mIsFocused) {
                    mSkipTextChangeEvent = false;
                } else {
                    if (mSearchInput.getText().toString().length() != 0
                            && mClearButton.getVisibility() == View.INVISIBLE) {
                        mClearButton.setAlpha(0.0f);
                        mClearButton.setVisibility(View.VISIBLE);
                        ViewCompat.animate(mClearButton).alpha(1.0f).setDuration(CLEAR_BTN_FADE_ANIM_DURATION)
                                .start();
                    } else if (mSearchInput.getText().toString().length() == 0) {
                        mClearButton.setVisibility(View.INVISIBLE);
                    }

                    if (mQueryListener != null && mIsFocused
                            && !mOldQuery.equals(mSearchInput.getText().toString())) {
                        mQueryListener.onSearchTextChanged(mOldQuery, mSearchInput.getText().toString());
                    }
                }

                mOldQuery = mSearchInput.getText().toString();
            }
        });

        mSearchInput.setOnFocusChangeListener(new TextView.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {

                if (mSkipQueryFocusChangeEvent) {
                    mSkipQueryFocusChangeEvent = false;
                } else if (hasFocus != mIsFocused) {
                    setSearchFocusedInternal(hasFocus);
                }
            }
        });

        mSearchInput.setOnKeyboardDismissedListener(new SearchInputView.OnKeyboardDismissedListener() {
            @Override
            public void onKeyboardDismissed() {
                if (mCloseSearchOnSofteKeyboardDismiss) {
                    setSearchFocusedInternal(false);
                }
            }
        });

        mSearchInput.setOnSearchKeyListener(new SearchInputView.OnKeyboardSearchKeyClickListener() {
            @Override
            public void onSearchKeyClicked() {
                if (mSearchListener != null) {
                    mSearchListener.onSearchAction(getQuery());
                }
                mSkipTextChangeEvent = true;
                mSkipTextChangeEvent = true;
                if (mIsTitleSet) {
                    setSearchBarTitle(getQuery());
                } else {
                    setSearchText(getQuery());
                }
                setSearchFocusedInternal(false);
            }
        });

        mLeftAction.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                if (isSearchBarFocused()) {
                    setSearchFocusedInternal(false);
                } else {
                    switch (mLeftActionMode) {
                    case LEFT_ACTION_MODE_SHOW_HAMBURGER:
                        toggleLeftMenu();
                        break;
                    case LEFT_ACTION_MODE_SHOW_SEARCH:
                        setSearchFocusedInternal(true);
                        break;
                    case LEFT_ACTION_MODE_SHOW_HOME:
                        if (mOnHomeActionClickListener != null) {
                            mOnHomeActionClickListener.onHomeClicked();
                        }
                        break;
                    case LEFT_ACTION_MODE_NO_LEFT_ACTION:
                        //do nothing
                        break;
                    }
                }
            }
        });

        refreshLeftIcon(false);
    }

    private void refreshSearchInputPaddingEnd(int menuItemsWidth) {
        if (menuItemsWidth == 0) {
            mClearButton.setTranslationX(-Util.dpToPx(4));
            int paddingRight = Util.dpToPx(4);
            if (mIsFocused) {
                paddingRight += Util.dpToPx(CLEAR_BTN_WIDTH);
            } else {
                paddingRight += Util.dpToPx(14);
            }
            mSearchInput.setPadding(0, 0, paddingRight, 0);
        } else {
            mClearButton.setTranslationX(-menuItemsWidth);
            int paddingRight = menuItemsWidth;
            if (mIsFocused) {
                paddingRight += Util.dpToPx(CLEAR_BTN_WIDTH);
            }
            mSearchInput.setPadding(0, 0, paddingRight, 0);
        }
    }

    private int actionMenuAvailWidth() {
        if (isInEditMode()) {
            return mQuerySection.getMeasuredWidth() / 2;
        }
        return mQuerySection.getWidth() / 2;
    }

    /**
     * Sets the menu button's color.
     *
     * @param color the color to be applied to the left menu button.
     */
    public void setLeftActionIconColor(int color) {
        mLeftActionIconColor = color;
        mMenuBtnDrawable.setColor(color);
        DrawableCompat.setTint(mIconBackArrow, color);
        DrawableCompat.setTint(mIconSearch, color);
    }

    /**
     * Sets the clear button's color.
     *
     * @param color the color to be applied to the clear button.
     */
    public void setClearBtnColor(int color) {
        mClearBtnColor = color;
        DrawableCompat.setTint(mIconClear, mClearBtnColor);
    }

    /**
     * Sets the action menu icons' color.
     *
     * @param color the color to be applied to the action menu items.
     */
    public void setMenuItemIconColor(int color) {
        this.mActionMenuItemColor = color;
        if (mMenuView != null) {
            mMenuView.setActionIconColor(this.mActionMenuItemColor);
        }
    }

    /**
     * Sets the action menu overflow icon's color.
     *
     * @param color the color to be applied to the overflow icon.
     */
    public void setActionMenuOverflowColor(int color) {
        this.mOverflowIconColor = color;
        if (mMenuView != null) {
            mMenuView.setOverflowColor(this.mOverflowIconColor);
        }
    }

    /**
     * Sets the background color of the search view including the suggestions section.
     *
     * @param color the color to be applied to the search bar and the suggestion section background.
     */
    public void setBackgroundColor(int color) {
        mBackgroundColor = color;
        if (mQuerySection != null) {
            mQuerySection.setCardBackgroundColor(color);
        }
    }

    /**
     * Sets the text color of the search and suggestion text.
     *
     * @param color the color to be applied to the search and suggestion text.
     */
    public void setViewTextColor(int color) {
        setQueryTextColor(color);
    }

    /**
     * Sets the text color of the search text.
     */
    public void setQueryTextColor(int color) {
        mSearchInputTextColor = color;
        if (mSearchInput != null) {
            mSearchInput.setTextColor(mSearchInputTextColor);
        }
    }

    /**
     * Sets the text color of the search hint.
     *
     * @param color the color to be applied to the search hint.
     */
    public void setHintTextColor(int color) {
        this.mSearchInputHintColor = color;
        if (mSearchInput != null) {
            mSearchInput.setHintTextColor(color);
        }
    }

    /**
     * Sets the color of the search divider that divides the search section from the suggestions.
     *
     * @param color the color to be applied the divider.
     */
    public void setDividerColor(int color) {
        mDividerColor = color;
        if (mDivider != null) {
            mDivider.setBackgroundColor(mDividerColor);
        }
    }

    /**
     * Set the mode for the left action button.
     */
    public void setLeftActionMode(@LeftActionMode int mode) {
        if (mode == mLeftActionMode) {
            return;
        }
        boolean showAnim = false;
        if ((mLeftActionMode == LEFT_ACTION_MODE_SHOW_HOME && mode == LEFT_ACTION_MODE_SHOW_HAMBURGER)
                || (mLeftActionMode == LEFT_ACTION_MODE_SHOW_HAMBURGER && mode == LEFT_ACTION_MODE_SHOW_HOME)) {
            showAnim = true;
        }
        mLeftActionMode = mode;
        refreshLeftIcon(showAnim);
    }

    private void refreshLeftIcon(boolean showAnim) {
        int leftActionWidthAndMarginLeft = Util.dpToPx(LEFT_MENU_WIDTH_AND_MARGIN_START);
        int queryTranslationX = 0;

        mLeftAction.setVisibility(VISIBLE);
        switch (mLeftActionMode) {
        case LEFT_ACTION_MODE_SHOW_HAMBURGER:
            if (showAnim && mMenuBtnDrawable.getProgress() == 1.0f) {
                ValueAnimator anim = ValueAnimator.ofFloat(1.0f, 0.0f);
                anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (Float) animation.getAnimatedValue();
                        mMenuBtnDrawable.setProgress(value);
                    }
                });
                anim.setDuration(MENU_ICON_ANIM_DURATION);
                anim.start();
                break;
            }
            mLeftAction.setImageDrawable(mMenuBtnDrawable);
            mMenuBtnDrawable.setProgress(0.0f);
            break;
        case LEFT_ACTION_MODE_SHOW_SEARCH:
            mLeftAction.setImageDrawable(mIconSearch);
            break;
        case LEFT_ACTION_MODE_SHOW_HOME:
            if (showAnim && mMenuBtnDrawable.getProgress() == 0.0f) {
                ValueAnimator anim = ValueAnimator.ofFloat(0.0f, 1.0f);
                anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (Float) animation.getAnimatedValue();
                        mMenuBtnDrawable.setProgress(value);
                    }
                });
                anim.setDuration(MENU_ICON_ANIM_DURATION);
                anim.start();
                break;
            }
            mLeftAction.setImageDrawable(mMenuBtnDrawable);
            mMenuBtnDrawable.setProgress(1.0f);
            break;
        case LEFT_ACTION_MODE_NO_LEFT_ACTION:
            mLeftAction.setVisibility(View.INVISIBLE);
            queryTranslationX = -leftActionWidthAndMarginLeft;
            break;
        }
        mSearchInputParent.setTranslationX(queryTranslationX);
    }

    private void toggleLeftMenu() {
        if (mMenuOpen) {
            closeMenu(true);
        } else {
            openMenu(true);
        }
    }

    /**
     * <p></p> Enables clients to directly manipulate the menu icon's progress. <p></p> Useful for custom animation/behaviors.
     *
     * @param progress the desired progress of the menu icon's rotation: 0.0 == hamburger shape, 1.0 == back arrow shape
     */
    public void setMenuIconProgress(float progress) {
        mMenuBtnDrawable.setProgress(progress);
        if (progress == 0) {
            closeMenu(false);
        } else if (progress == 1.0) {
            openMenu(false);
        }
    }

    /**
     * Mimics a menu click that opens the menu. Useful when for navigation drawers when they open as a result of dragging.
     */
    public void openMenu(boolean withAnim) {
        mMenuOpen = true;
        openMenuDrawable(mMenuBtnDrawable, withAnim);
        if (mOnMenuClickListener != null) {
            mOnMenuClickListener.onMenuOpened();
        }
    }

    /**
     * Mimics a menu click that closes. Useful when fo navigation drawers when they close as a result of selecting and item.
     *
     * @param withAnim true, will close the menu button with the  Material animation
     */
    public void closeMenu(boolean withAnim) {
        mMenuOpen = false;
        closeMenuDrawable(mMenuBtnDrawable, withAnim);
        if (mOnMenuClickListener != null) {
            mOnMenuClickListener.onMenuClosed();
        }
    }

    /**
     * Set the hamburger menu to open or closed without animating hamburger to arrow and without calling listeners.
     */
    public void setLeftMenuOpen(boolean isOpen) {
        mMenuOpen = isOpen;
        mMenuBtnDrawable.setProgress(isOpen ? 1.0f : 0.0f);
    }

    /**
     * Shows a circular progress on top of the menu action button. <p></p> Call hidProgress() to change back to normal and make the menu
     * action visible.
     */
    public void showProgress() {
        if (mSearchProgress.getVisibility() != View.GONE) {
            return;
        }
        mLeftAction.setVisibility(View.GONE);
        mSearchProgress.setAlpha(0.0f);
        mSearchProgress.setVisibility(View.VISIBLE);
        ObjectAnimator.ofFloat(mSearchProgress, "alpha", 0.0f, 1.0f).start();
    }

    /**
     * Hides the progress bar after a prior call to showProgress()
     */
    public void hideProgress() {
        if (mSearchProgress.getVisibility() != View.VISIBLE) {
            return;
        }
        mSearchProgress.setVisibility(View.GONE);
        mLeftAction.setAlpha(0.0f);
        mLeftAction.setVisibility(View.VISIBLE);
        ObjectAnimator.ofFloat(mLeftAction, "alpha", 0.0f, 1.0f).start();
    }

    /**
     * Inflates the menu items from an xml resource.
     *
     * @param menuId a menu xml resource reference
     */
    public void inflateOverflowMenu(int menuId) {
        mMenuId = menuId;
        mMenuView.reset(menuId, actionMenuAvailWidth());
        if (mIsFocused) {
            mMenuView.hideIfRoomItems(false);
        }
    }

    /**
     * Set a hint that will appear in the search input. Default hint is R.string.abc_search_hint which is "search..." (when device language
     * is set to english)
     */
    public void setSearchHint(String searchHint) {
        mSearchHint = searchHint != null ? searchHint : getResources().getString(R.string.abc_search_hint);
        mSearchInput.setHint(mSearchHint);
    }

    /**
     * Sets whether the the button with the search icon will appear in the soft-keyboard or not.
     *
     * @param show to show the search button in the soft-keyboard.
     */
    public void setShowSearchKey(boolean show) {
        mShowSearchKey = show;
        if (show) {
            mSearchInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
        } else {
            mSearchInput.setImeOptions(EditorInfo.IME_ACTION_NONE);
        }
    }

    /**
     * Sets whether the search will lose focus when the softkeyboard gets closed from a back press
     */
    public void setCloseSearchOnKeyboardDismiss(boolean closeSearchOnKeyboardDismiss) {
        this.mCloseSearchOnSofteKeyboardDismiss = closeSearchOnKeyboardDismiss;
    }

    /**
     * Set whether a touch outside of the search bar's bounds will cause the search bar to loos focus.
     *
     * @param enable true to dismiss on outside touch, false otherwise.
     */
    public void setDismissOnOutsideClick(boolean enable) {
        mDismissOnOutsideTouch = enable;
    }

    /**
     * Wrapper implementation for EditText.setFocusable(boolean focusable)
     *
     * @param focusable true, to make search focus when clicked.
     */
    public void setSearchFocusable(boolean focusable) {
        mSearchInput.setFocusable(focusable);
    }

    /**
     * Sets the title for the search bar. <p></p> Note that after the title is set, when the search gains focus, the title will be replaced
     * by the search hint.
     *
     * @param title the title to be shown when search is not focused
     */
    public void setSearchBarTitle(CharSequence title) {
        this.mTitleText = title.toString();
        mIsTitleSet = true;
        mSearchInput.setText(title);
    }

    /**
     * Sets the search text. <p></p> Note that this is the different from {@link #setSearchBarTitle(CharSequence title) setSearchBarTitle}
     * in that it keeps the text when the search gains focus.
     *
     * @param text the text to be set for the search input.
     */
    public void setSearchText(CharSequence text) {
        mIsTitleSet = false;
        mSearchInput.setText(text);
    }

    /**
     * Sets the font in the search text field
     *
     * @param fontPath font path in the assets folder
     */
    public void setFont(String fontPath) {
        if (TextUtils.isEmpty(fontPath)) {
            return;
        }
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), fontPath);
        if (tf == null) {
            return;
        }
        mSearchInput.setTypeface(tf, Typeface.BOLD);
    }

    /**
     * Returns the current query text.
     *
     * @return the current query
     */
    public String getQuery() {
        return mOldQuery;
    }

    public void clearQuery() {
        mSearchInput.setText("");
    }

    /**
     * Sets whether the search is focused or not.
     *
     * @param focused true, to set the search to be active/focused.
     * @return true if the search was focused and will now become not focused. Useful for calling supper.onBackPress() in the hosting
     * activity only if this method returns false
     */
    public boolean setSearchFocused(final boolean focused) {

        boolean updatedToNotFocused = !focused && this.mIsFocused;

        if ((focused != this.mIsFocused)) {
            setSearchFocusedInternal(focused);
        }
        return updatedToNotFocused;
    }

    public void clearSearchFocus() {
        setSearchFocusedInternal(false);
    }

    public boolean isSearchBarFocused() {
        return mIsFocused;
    }

    private void setSearchFocusedInternal(final boolean focused) {
        this.mIsFocused = focused;

        if (focused) {
            mSearchInput.requestFocus();
            refreshSearchInputPaddingEnd(0);//this must be called before  mMenuView.hideIfRoomItems(...)
            mMenuView.hideIfRoomItems(true);
            transitionInLeftSection(true);
            Util.showSoftKeyboard(getContext(), mSearchInput);
            if (mMenuOpen) {
                closeMenu(false);
            }
            if (mIsTitleSet) {
                mSkipTextChangeEvent = true;
                mSearchInput.setText("");
            }
            mClearButton.setVisibility(
                    (mSearchInput.getText().toString().length() == 0) ? View.INVISIBLE : View.VISIBLE);
            if (mFocusChangeListener != null) {
                mFocusChangeListener.onFocus();
            }
        } else {
            mMainLayout.requestFocus();
            refreshSearchInputPaddingEnd(0);//this must be called before  mMenuView.hideIfRoomItems(...)
            mMenuView.showIfRoomItems(true);
            transitionOutLeftSection(true);
            mClearButton.setVisibility(View.GONE);
            if (mHostActivity != null) {
                Util.closeSoftKeyboard(mHostActivity);
            }
            if (mIsTitleSet) {
                mSkipTextChangeEvent = true;
                mSearchInput.setText(mTitleText);
            }
            if (mFocusChangeListener != null) {
                mFocusChangeListener.onFocusCleared();
            }
        }
    }

    private void changeIcon(ImageView imageView, Drawable newIcon, boolean withAnim) {
        imageView.setImageDrawable(newIcon);
        if (withAnim) {
            ObjectAnimator fadeInVoiceInputOrClear = ObjectAnimator.ofFloat(imageView, "alpha", 0.0f, 1.0f);
            fadeInVoiceInputOrClear.start();
        } else {
            imageView.setAlpha(1.0f);
        }
    }

    private void transitionInLeftSection(boolean withAnim) {

        if (mSearchProgress.getVisibility() != View.VISIBLE) {
            mLeftAction.setVisibility(View.VISIBLE);
        } else {
            mLeftAction.setVisibility(View.INVISIBLE);
        }

        switch (mLeftActionMode) {
        case LEFT_ACTION_MODE_SHOW_HAMBURGER:
            openMenuDrawable(mMenuBtnDrawable, withAnim);
            if (!mMenuOpen) {
                break;
            }
            break;
        case LEFT_ACTION_MODE_SHOW_SEARCH:
            mLeftAction.setImageDrawable(mIconBackArrow);
            if (withAnim) {
                mLeftAction.setRotation(45);
                mLeftAction.setAlpha(0.0f);
                ObjectAnimator rotateAnim = ViewPropertyObjectAnimator.animate(mLeftAction).rotation(0).get();
                ObjectAnimator fadeAnim = ViewPropertyObjectAnimator.animate(mLeftAction).alpha(1.0f).get();
                AnimatorSet animSet = new AnimatorSet();
                animSet.setDuration(500);
                animSet.playTogether(rotateAnim, fadeAnim);
                animSet.start();
            }
            break;
        case LEFT_ACTION_MODE_SHOW_HOME:
            //do nothing
            break;
        case LEFT_ACTION_MODE_NO_LEFT_ACTION:
            mLeftAction.setImageDrawable(mIconBackArrow);

            if (withAnim) {
                ObjectAnimator searchInputTransXAnim = ViewPropertyObjectAnimator.animate(mSearchInputParent)
                        .translationX(0).get();

                mLeftAction.setScaleX(0.5f);
                mLeftAction.setScaleY(0.5f);
                mLeftAction.setAlpha(0.0f);
                mLeftAction.setTranslationX(Util.dpToPx(8));
                ObjectAnimator transXArrowAnim = ViewPropertyObjectAnimator.animate(mLeftAction).translationX(1.0f)
                        .get();
                ObjectAnimator scaleXArrowAnim = ViewPropertyObjectAnimator.animate(mLeftAction).scaleX(1.0f).get();
                ObjectAnimator scaleYArrowAnim = ViewPropertyObjectAnimator.animate(mLeftAction).scaleY(1.0f).get();
                ObjectAnimator fadeArrowAnim = ViewPropertyObjectAnimator.animate(mLeftAction).alpha(1.0f).get();
                transXArrowAnim.setStartDelay(150);
                scaleXArrowAnim.setStartDelay(150);
                scaleYArrowAnim.setStartDelay(150);
                fadeArrowAnim.setStartDelay(150);

                AnimatorSet animSet = new AnimatorSet();
                animSet.setDuration(500);
                animSet.playTogether(searchInputTransXAnim, transXArrowAnim, scaleXArrowAnim, scaleYArrowAnim,
                        fadeArrowAnim);
                animSet.start();
            } else {
                mSearchInputParent.setTranslationX(0);
            }
            break;
        }
    }

    private void transitionOutLeftSection(boolean withAnim) {

        switch (mLeftActionMode) {
        case LEFT_ACTION_MODE_SHOW_HAMBURGER:
            closeMenuDrawable(mMenuBtnDrawable, withAnim);
            break;
        case LEFT_ACTION_MODE_SHOW_SEARCH:
            changeIcon(mLeftAction, mIconSearch, withAnim);
            break;
        case LEFT_ACTION_MODE_SHOW_HOME:
            //do nothing
            break;
        case LEFT_ACTION_MODE_NO_LEFT_ACTION:
            mLeftAction.setImageDrawable(mIconBackArrow);

            if (withAnim) {
                ObjectAnimator searchInputTransXAnim = ViewPropertyObjectAnimator.animate(mSearchInputParent)
                        .translationX(-Util.dpToPx(LEFT_MENU_WIDTH_AND_MARGIN_START)).get();

                ObjectAnimator scaleXArrowAnim = ViewPropertyObjectAnimator.animate(mLeftAction).scaleX(0.5f).get();
                ObjectAnimator scaleYArrowAnim = ViewPropertyObjectAnimator.animate(mLeftAction).scaleY(0.5f).get();
                ObjectAnimator fadeArrowAnim = ViewPropertyObjectAnimator.animate(mLeftAction).alpha(0.5f).get();
                scaleXArrowAnim.setDuration(300);
                scaleYArrowAnim.setDuration(300);
                fadeArrowAnim.setDuration(300);
                scaleXArrowAnim.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {

                        //restore normal state
                        mLeftAction.setScaleX(1.0f);
                        mLeftAction.setScaleY(1.0f);
                        mLeftAction.setAlpha(1.0f);
                        mLeftAction.setVisibility(View.INVISIBLE);
                    }
                });

                AnimatorSet animSet = new AnimatorSet();
                animSet.setDuration(350);
                animSet.playTogether(scaleXArrowAnim, scaleYArrowAnim, fadeArrowAnim, searchInputTransXAnim);
                animSet.start();
            } else {
                mLeftAction.setVisibility(View.INVISIBLE);
            }
            break;
        }
    }

    /**
     * Sets the listener that will listen for query changes as they are being typed.
     *
     * @param listener listener for query changes
     */
    public void setOnQueryChangeListener(OnQueryChangeListener listener) {
        this.mQueryListener = listener;
    }

    /**
     * Sets the listener that will be called when an action that completes the current search session has occurred and the search lost
     * focus. <p></p> <p>When called, a client would ideally grab the search or suggestion query from the callback parameter or from {@link
     * #getQuery() getquery} and perform the necessary query against its data source.</p>
     *
     * @param listener listener for query completion
     */
    public void setOnSearchListener(OnSearchListener listener) {
        this.mSearchListener = listener;
    }

    /**
     * Sets the listener that will be called when the focus of the search has changed.
     *
     * @param listener listener for search focus changes
     */
    public void setOnFocusChangeListener(OnFocusChangeListener listener) {
        this.mFocusChangeListener = listener;
    }

    /**
     * Sets the listener that will be called when the left/start menu (or navigation menu) is clicked. <p></p> <p>Note that this is
     * different from the overflow menu that has a separate listener.</p>
     */
    public void setOnLeftMenuClickListener(OnLeftMenuClickListener listener) {
        this.mOnMenuClickListener = listener;
    }

    /**
     * Sets the listener that will be called when the left/start home action (back arrow) is clicked.
     */
    public void setOnHomeActionClickListener(OnHomeActionClickListener listener) {
        this.mOnHomeActionClickListener = listener;
    }

    /**
     * Sets the listener that will be called when an item in the overflow menu is clicked.
     *
     * @param listener listener to listen to menu item clicks
     */
    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
        this.mActionMenuItemListener = listener;
        //todo reset menu view listener
    }

    private void openMenuDrawable(final DrawerArrowDrawable drawerArrowDrawable, boolean withAnim) {
        if (withAnim) {
            ValueAnimator anim = ValueAnimator.ofFloat(0.0f, 1.0f);
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {

                    float value = (Float) animation.getAnimatedValue();
                    drawerArrowDrawable.setProgress(value);
                }
            });
            anim.setDuration(MENU_ICON_ANIM_DURATION);
            anim.start();
        } else {
            drawerArrowDrawable.setProgress(1.0f);
        }
    }

    private void closeMenuDrawable(final DrawerArrowDrawable drawerArrowDrawable, boolean withAnim) {
        if (withAnim) {
            ValueAnimator anim = ValueAnimator.ofFloat(1.0f, 0.0f);
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {

                    float value = (Float) animation.getAnimatedValue();
                    drawerArrowDrawable.setProgress(value);
                }
            });
            anim.setDuration(MENU_ICON_ANIM_DURATION);
            anim.start();
        } else {
            drawerArrowDrawable.setProgress(0.0f);
        }
    }

    private void fadeOutBackground() {
        ValueAnimator anim = ValueAnimator.ofInt(BACKGROUND_DRAWABLE_ALPHA_SEARCH_FOCUSED,
                BACKGROUND_DRAWABLE_ALPHA_SEARCH_NOT_FOCUSED);
        anim.setDuration(BACKGROUND_FADE_ANIM_DURATION);
        anim.start();
    }

    private void fadeInBackground() {
        ValueAnimator anim = ValueAnimator.ofInt(BACKGROUND_DRAWABLE_ALPHA_SEARCH_NOT_FOCUSED,
                BACKGROUND_DRAWABLE_ALPHA_SEARCH_FOCUSED);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

                int value = (Integer) animation.getAnimatedValue();
            }
        });
        anim.setDuration(BACKGROUND_FADE_ANIM_DURATION);
        anim.start();
    }

    private boolean isRTL() {

        Configuration config = getResources().getConfiguration();
        return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState savedState = new SavedState(superState);
        savedState.isFocused = this.mIsFocused;
        savedState.query = getQuery();
        savedState.searchHint = this.mSearchHint;
        savedState.dismissOnOutsideClick = this.mDismissOnOutsideTouch;
        savedState.showSearchKey = this.mShowSearchKey;
        savedState.isTitleSet = this.mIsTitleSet;
        savedState.backgroundColor = this.mBackgroundColor;
        savedState.queryTextColor = this.mSearchInputTextColor;
        savedState.searchHintTextColor = this.mSearchInputHintColor;
        savedState.actionOverflowMenueColor = this.mOverflowIconColor;
        savedState.menuItemIconColor = this.mActionMenuItemColor;
        savedState.leftIconColor = this.mLeftActionIconColor;
        savedState.clearBtnColor = this.mClearBtnColor;
        savedState.dividerColor = this.mDividerColor;
        savedState.menuId = mMenuId;
        savedState.leftActionMode = mLeftActionMode;
        savedState.dismissOnSoftKeyboardDismiss = this.mDismissOnOutsideTouch;
        return savedState;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        final SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());

        this.mIsFocused = savedState.isFocused;
        this.mIsTitleSet = savedState.isTitleSet;
        this.mMenuId = savedState.menuId;
        setDismissOnOutsideClick(savedState.dismissOnOutsideClick);
        setShowSearchKey(savedState.showSearchKey);
        setSearchHint(savedState.searchHint);
        setBackgroundColor(savedState.backgroundColor);
        setQueryTextColor(savedState.queryTextColor);
        setHintTextColor(savedState.searchHintTextColor);
        setActionMenuOverflowColor(savedState.actionOverflowMenueColor);
        setMenuItemIconColor(savedState.menuItemIconColor);
        setLeftActionIconColor(savedState.leftIconColor);
        setClearBtnColor(savedState.clearBtnColor);
        setDividerColor(savedState.dividerColor);
        setLeftActionMode(savedState.leftActionMode);
        setCloseSearchOnKeyboardDismiss(savedState.dismissOnSoftKeyboardDismiss);

        if (this.mIsFocused) {

            mSkipTextChangeEvent = true;
            mSkipQueryFocusChangeEvent = true;

            mClearButton.setVisibility((savedState.query.length() == 0) ? View.INVISIBLE : View.VISIBLE);
            mLeftAction.setVisibility(View.VISIBLE);

            Util.showSoftKeyboard(getContext(), mSearchInput);
        }
    }

    private DrawerLayout.DrawerListener mDrawerListener = new DrawerListener();

    public void attachNavigationDrawerToMenuButton(@NonNull DrawerLayout drawerLayout) {
        drawerLayout.addDrawerListener(mDrawerListener);
        setOnLeftMenuClickListener(new NavDrawerLeftMenuClickListener(drawerLayout));
    }

    public void detachNavigationDrawerFromMenuButton(@NonNull DrawerLayout drawerLayout) {
        drawerLayout.removeDrawerListener(mDrawerListener);
        setOnLeftMenuClickListener(null);
    }

    static class SavedState extends BaseSavedState {

        private boolean isFocused;
        private String query;
        private String searchHint;
        private boolean dismissOnOutsideClick;
        private boolean showSearchKey;
        private boolean isTitleSet;
        private int backgroundColor;
        private int queryTextColor;
        private int searchHintTextColor;
        private int actionOverflowMenueColor;
        private int menuItemIconColor;
        private int leftIconColor;
        private int clearBtnColor;
        private int dividerColor;
        private int menuId;
        private int leftActionMode;
        private boolean dismissOnSoftKeyboardDismiss;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            isFocused = (in.readInt() != 0);
            query = in.readString();
            searchHint = in.readString();
            dismissOnOutsideClick = (in.readInt() != 0);
            showSearchKey = (in.readInt() != 0);
            isTitleSet = (in.readInt() != 0);
            backgroundColor = in.readInt();
            queryTextColor = in.readInt();
            searchHintTextColor = in.readInt();
            actionOverflowMenueColor = in.readInt();
            menuItemIconColor = in.readInt();
            leftIconColor = in.readInt();
            clearBtnColor = in.readInt();
            dividerColor = in.readInt();
            menuId = in.readInt();
            leftActionMode = in.readInt();
            dismissOnSoftKeyboardDismiss = (in.readInt() != 0);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(isFocused ? 1 : 0);
            out.writeString(query);
            out.writeString(searchHint);
            out.writeInt(dismissOnOutsideClick ? 1 : 0);
            out.writeInt(showSearchKey ? 1 : 0);
            out.writeInt(isTitleSet ? 1 : 0);
            out.writeInt(backgroundColor);
            out.writeInt(queryTextColor);
            out.writeInt(searchHintTextColor);
            out.writeInt(actionOverflowMenueColor);
            out.writeInt(menuItemIconColor);
            out.writeInt(leftIconColor);
            out.writeInt(clearBtnColor);
            out.writeInt(dividerColor);
            out.writeInt(menuId);
            out.writeInt(leftActionMode);
            out.writeInt(dismissOnSoftKeyboardDismiss ? 1 : 0);
        }

        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

    private class DrawerListener implements DrawerLayout.DrawerListener {

        @Override
        public void onDrawerSlide(View drawerView, float slideOffset) {
            setMenuIconProgress(slideOffset);
        }

        @Override
        public void onDrawerOpened(View drawerView) {

        }

        @Override
        public void onDrawerClosed(View drawerView) {

        }

        @Override
        public void onDrawerStateChanged(int newState) {

        }
    }

    private class NavDrawerLeftMenuClickListener implements OnLeftMenuClickListener {

        DrawerLayout mDrawerLayout;

        public NavDrawerLeftMenuClickListener(DrawerLayout drawerLayout) {
            mDrawerLayout = drawerLayout;
        }

        @Override
        public void onMenuOpened() {
            mDrawerLayout.openDrawer(GravityCompat.START);
        }

        @Override
        public void onMenuClosed() {
            //do nothing
        }
    }
}