1e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet/*
2e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * Copyright (C) 2014 The Android Open Source Project
3e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet *
4e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * Licensed under the Apache License, Version 2.0 (the "License");
5e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * you may not use this file except in compliance with the License.
6e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * You may obtain a copy of the License at
7e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet *
8e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet *      http://www.apache.org/licenses/LICENSE-2.0
9e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet *
10e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * Unless required by applicable law or agreed to in writing, software
11e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * distributed under the License is distributed on an "AS IS" BASIS,
12e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * See the License for the specific language governing permissions and
14e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet * limitations under the License.
15e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet */
16e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
17e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichetpackage android.support.v17.leanback.widget;
18e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
19aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stoutimport android.animation.ArgbEvaluator;
20aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stoutimport android.animation.ValueAnimator;
21e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichetimport android.content.Context;
225a59bde085588f95dc067bd1ed64a940f355343cbulicimport android.content.res.Resources;
23f0e71182c62bba18e9d8098941a29c4f5031ce36Jerome Poichetimport android.content.res.TypedArray;
24aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stoutimport android.graphics.Color;
25e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichetimport android.graphics.Rect;
26f0e71182c62bba18e9d8098941a29c4f5031ce36Jerome Poichetimport android.graphics.drawable.Drawable;
274cf79b1c4d38a190317961891f9fd052836710fdCraig Stoutimport android.graphics.drawable.GradientDrawable;
2870acb0c19be3831a2080e4f902324de16bfbf62eTor Norbyeimport android.support.annotation.ColorInt;
29e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichetimport android.support.v17.leanback.R;
30e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichetimport android.util.AttributeSet;
31e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichetimport android.view.LayoutInflater;
32e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichetimport android.view.View;
334cf79b1c4d38a190317961891f9fd052836710fdCraig Stoutimport android.widget.FrameLayout;
34f0e71182c62bba18e9d8098941a29c4f5031ce36Jerome Poichetimport android.widget.ImageView;
35e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
36937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet/**
37937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet * <p>A widget that draws a search affordance, represented by a round background and an icon.</p>
38937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet *
39a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * The background color and icon can be customized.
40937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet */
414cf79b1c4d38a190317961891f9fd052836710fdCraig Stoutpublic class SearchOrbView extends FrameLayout implements View.OnClickListener {
42e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    private OnClickListener mListener;
43558f7b70035c50045908efca5f4f3d65df685cacCraig Stout    private View mRootView;
444cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    private View mSearchOrbView;
45937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    private ImageView mIcon;
46937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    private Drawable mIconDrawable;
474fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    private Colors mColors;
484cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    private final float mFocusedZoom;
49aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout    private final int mPulseDurationMs;
5044f004b2612b04510a09a4c1e33f5a109582d669Craig Stout    private final int mScaleDurationMs;
51c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout    private final float mUnfocusedZ;
52c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout    private final float mFocusedZ;
53aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout    private ValueAnimator mColorAnimator;
5477b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov    private boolean mColorAnimationEnabled;
5577b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov    private boolean mAttachedToWindow;
56aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout
574fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    /**
584fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * A set of colors used to display the search orb.
594fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     */
604fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    public static class Colors {
614fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        private static final float sBrightnessAlpha = 0.15f;
624fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
634fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        /**
644fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * Constructs a color set using the given color for the search orb.
654fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * Other colors are provided by the framework.
66c4788eac909f51e73e05885314d3ace65d0a2f26bulic         *
674fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * @param color The main search orb color.
684fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         */
6970acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye        public Colors(@ColorInt int color) {
704fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            this(color, color);
714fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        }
724fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
734fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        /**
744fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * Constructs a color set using the given colors for the search orb.
754fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * Other colors are provided by the framework.
76c4788eac909f51e73e05885314d3ace65d0a2f26bulic         *
774fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * @param color The main search orb color.
784fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * @param brightColor A brighter version of the search orb used for animation.
794fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         */
8070acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye        public Colors(@ColorInt int color, @ColorInt int brightColor) {
814fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            this(color, brightColor, Color.TRANSPARENT);
824fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        }
834fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
844fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        /**
854fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * Constructs a color set using the given colors.
864fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         *
874fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * @param color The main search orb color.
884fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * @param brightColor A brighter version of the search orb used for animation.
894fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * @param iconColor A color used to tint the search orb icon.
904fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         */
9170acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye        public Colors(@ColorInt int color, @ColorInt int brightColor, @ColorInt int iconColor) {
924fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            this.color = color;
934fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            this.brightColor = brightColor == color ? getBrightColor(color) : brightColor;
944fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            this.iconColor = iconColor;
954fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        }
964fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
974fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        /**
984fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * The main color of the search orb.
994fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         */
10070acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye        @ColorInt
1014fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        public int color;
1024fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
1034fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        /**
1044fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * A brighter version of the search orb used for animation.
1054fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         */
10670acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye        @ColorInt
1074fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        public int brightColor;
1084fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
1094fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        /**
1104fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * A color used to tint the search orb icon.
1114fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         */
11270acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye        @ColorInt
1134fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        public int iconColor;
1144fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
1154fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        /**
1164fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         * Computes a default brighter version of the given color.
1174fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout         */
1184fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        public static int getBrightColor(int color) {
1194fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            final float brightnessValue = 0xff * sBrightnessAlpha;
1204fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            int red = (int)(Color.red(color) * (1 - sBrightnessAlpha) + brightnessValue);
1214fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            int green = (int)(Color.green(color) * (1 - sBrightnessAlpha) + brightnessValue);
1224fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            int blue = (int)(Color.blue(color) * (1 - sBrightnessAlpha) + brightnessValue);
1234fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            int alpha = (int)(Color.alpha(color) * (1 - sBrightnessAlpha) + brightnessValue);
1244fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            return Color.argb(alpha, red, green, blue);
1254fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        }
1264fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    }
1274fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
128aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout    private final ArgbEvaluator mColorEvaluator = new ArgbEvaluator();
129aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout
130aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout    private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
131aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout            new ValueAnimator.AnimatorUpdateListener() {
132aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout        @Override
133aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout        public void onAnimationUpdate(ValueAnimator animator) {
134aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout            Integer color = (Integer) animator.getAnimatedValue();
135aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout            setOrbViewColor(color.intValue());
136aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout        }
137aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout    };
138e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
13969e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout    private ValueAnimator mShadowFocusAnimator;
14069e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout
14169e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout    private final ValueAnimator.AnimatorUpdateListener mFocusUpdateListener =
14269e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout            new ValueAnimator.AnimatorUpdateListener() {
14369e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        @Override
14469e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        public void onAnimationUpdate(ValueAnimator animation) {
145c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout            setSearchOrbZ(animation.getAnimatedFraction());
14669e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        }
14769e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout    };
14869e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout
149c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout    private void setSearchOrbZ(float fraction) {
150c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout        ShadowHelper.getInstance().setZ(mSearchOrbView,
151c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout                mUnfocusedZ + fraction * (mFocusedZ - mUnfocusedZ));
152c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout    }
153c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout
154e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    public SearchOrbView(Context context) {
155e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        this(context, null);
156e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    }
157e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
158e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    public SearchOrbView(Context context, AttributeSet attrs) {
159937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        this(context, attrs, R.attr.searchOrbViewStyle);
160e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    }
161e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
162937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    public SearchOrbView(Context context, AttributeSet attrs, int defStyleAttr) {
163937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        super(context, attrs, defStyleAttr);
164e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
1655a59bde085588f95dc067bd1ed64a940f355343cbulic        final Resources res = context.getResources();
1665a59bde085588f95dc067bd1ed64a940f355343cbulic
167e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        LayoutInflater inflater = (LayoutInflater) context
168e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1694c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        mRootView = inflater.inflate(getLayoutResourceId(), this, true);
170558f7b70035c50045908efca5f4f3d65df685cacCraig Stout        mSearchOrbView = mRootView.findViewById(R.id.search_orb);
171558f7b70035c50045908efca5f4f3d65df685cacCraig Stout        mIcon = (ImageView) mRootView.findViewById(R.id.icon);
172e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
173ed57770cf2211040bffe0bddd55e7c28fb47a42aJerome Poichet        mFocusedZoom = context.getResources().getFraction(
174ed57770cf2211040bffe0bddd55e7c28fb47a42aJerome Poichet                R.fraction.lb_search_orb_focused_zoom, 1, 1);
175ed57770cf2211040bffe0bddd55e7c28fb47a42aJerome Poichet        mPulseDurationMs = context.getResources().getInteger(
176ed57770cf2211040bffe0bddd55e7c28fb47a42aJerome Poichet                R.integer.lb_search_orb_pulse_duration_ms);
17744f004b2612b04510a09a4c1e33f5a109582d669Craig Stout        mScaleDurationMs = context.getResources().getInteger(
17844f004b2612b04510a09a4c1e33f5a109582d669Craig Stout                R.integer.lb_search_orb_scale_duration_ms);
179c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout        mFocusedZ = context.getResources().getDimensionPixelSize(
180c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout                R.dimen.lb_search_orb_focused_z);
181c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout        mUnfocusedZ = context.getResources().getDimensionPixelSize(
182c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout                R.dimen.lb_search_orb_unfocused_z);
183ed57770cf2211040bffe0bddd55e7c28fb47a42aJerome Poichet
184937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbSearchOrbView,
185937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet                defStyleAttr, 0);
1865a59bde085588f95dc067bd1ed64a940f355343cbulic
187f0e71182c62bba18e9d8098941a29c4f5031ce36Jerome Poichet        Drawable img = a.getDrawable(R.styleable.lbSearchOrbView_searchOrbIcon);
1885a59bde085588f95dc067bd1ed64a940f355343cbulic        if (img == null) {
1895a59bde085588f95dc067bd1ed64a940f355343cbulic            img = res.getDrawable(R.drawable.lb_ic_in_app_search);
1905a59bde085588f95dc067bd1ed64a940f355343cbulic        }
191937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        setOrbIcon(img);
192f0e71182c62bba18e9d8098941a29c4f5031ce36Jerome Poichet
1935a59bde085588f95dc067bd1ed64a940f355343cbulic        int defColor = res.getColor(R.color.lb_default_search_color);
1945a59bde085588f95dc067bd1ed64a940f355343cbulic        int color = a.getColor(R.styleable.lbSearchOrbView_searchOrbColor, defColor);
1958b55ff20146055bb0c4c5544814fcf530e03649abulic        int brightColor = a.getColor(
1964fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout                R.styleable.lbSearchOrbView_searchOrbBrightColor, color);
1974fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        int iconColor = a.getColor(R.styleable.lbSearchOrbView_searchOrbIconColor, Color.TRANSPARENT);
1984fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        setOrbColors(new Colors(color, brightColor, iconColor));
199f0e71182c62bba18e9d8098941a29c4f5031ce36Jerome Poichet        a.recycle();
200f0e71182c62bba18e9d8098941a29c4f5031ce36Jerome Poichet
201e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        setFocusable(true);
2024cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        setClipChildren(false);
203e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        setOnClickListener(this);
204c4788eac909f51e73e05885314d3ace65d0a2f26bulic        setSoundEffectsEnabled(false);
205c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout        setSearchOrbZ(0);
206c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout
20769e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        // Icon has no background, but must be on top of the search orb view
208c62efa44831b1c60dcbdfd968735e27ac8294439Craig Stout        ShadowHelper.getInstance().setZ(mIcon, mFocusedZ);
209e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    }
210e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
2114c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    int getLayoutResourceId() {
2124c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        return R.layout.lb_search_orb;
2134c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    }
2144c696a0ad561090035960c2f34a058562c7f2aadCraig Stout
2154c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    void scaleOrbViewOnly(float scale) {
2164c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        mSearchOrbView.setScaleX(scale);
2174c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        mSearchOrbView.setScaleY(scale);
2184c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    }
2194c696a0ad561090035960c2f34a058562c7f2aadCraig Stout
2204c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    float getFocusedZoom() {
2214c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        return mFocusedZoom;
2224c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    }
2234c696a0ad561090035960c2f34a058562c7f2aadCraig Stout
224e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    @Override
225e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    public void onClick(View view) {
226e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        if (null != mListener) {
227e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet            mListener.onClick(view);
228e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        }
229e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    }
230e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
23169e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout    private void startShadowFocusAnimation(boolean gainFocus, int duration) {
23269e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        if (mShadowFocusAnimator == null) {
23369e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout            mShadowFocusAnimator = ValueAnimator.ofFloat(0f, 1f);
23469e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout            mShadowFocusAnimator.addUpdateListener(mFocusUpdateListener);
23569e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        }
23669e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        if (gainFocus) {
23769e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout            mShadowFocusAnimator.start();
23869e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        } else {
23969e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout            mShadowFocusAnimator.reverse();
24069e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        }
24169e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout        mShadowFocusAnimator.setDuration(duration);
24269e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout    }
24369e74bd8956577d9a3414b81ec661fd5fee42e19Craig Stout
244e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    @Override
245e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
246e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
2474c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        animateOnFocus(gainFocus);
2484c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    }
2494c696a0ad561090035960c2f34a058562c7f2aadCraig Stout
2504c696a0ad561090035960c2f34a058562c7f2aadCraig Stout    void animateOnFocus(boolean hasFocus) {
2514c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        final float zoom = hasFocus ? mFocusedZoom : 1f;
25244f004b2612b04510a09a4c1e33f5a109582d669Craig Stout        mRootView.animate().scaleX(zoom).scaleY(zoom).setDuration(mScaleDurationMs).start();
2534c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        startShadowFocusAnimation(hasFocus, mScaleDurationMs);
2544c696a0ad561090035960c2f34a058562c7f2aadCraig Stout        enableOrbColorAnimation(hasFocus);
255aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout    }
256aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout
257937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    /**
258a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the orb icon.
259937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     * @param icon the drawable to be used as the icon
260937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     */
261937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    public void setOrbIcon(Drawable icon) {
262937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        mIconDrawable = icon;
263937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        mIcon.setImageDrawable(mIconDrawable);
264aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout    }
265aadb8928f5920c758c1a385bbc8b8b128a60657cCraig Stout
266937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    /**
267937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     * Returns the orb icon
268937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     * @return the drawable used as the icon
269937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     */
270937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    public Drawable getOrbIcon() {
271937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        return mIconDrawable;
272e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    }
273e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
274e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    /**
275a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the on click listener for the orb.
276e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet     * @param listener The listener.
277e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet     */
278e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    public void setOnOrbClickedListener(OnClickListener listener) {
279e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet        mListener = listener;
280e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet    }
281e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet
282937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    /**
2834fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Sets the background color of the search orb.
2844fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Other colors will be provided by the framework.
285c4788eac909f51e73e05885314d3ace65d0a2f26bulic     *
286937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     * @param color the RGBA color
287937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     */
2884cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    public void setOrbColor(int color) {
2894fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        setOrbColors(new Colors(color, color, Color.TRANSPARENT));
2908b55ff20146055bb0c4c5544814fcf530e03649abulic    }
2918b55ff20146055bb0c4c5544814fcf530e03649abulic
2924fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    /**
2934fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Sets the search orb colors.
2944fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Other colors are provided by the framework.
2954fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * @deprecated Use {@link #setOrbColors(Colors)} instead.
2964fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     */
2974fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    @Deprecated
29870acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    public void setOrbColor(@ColorInt int color, @ColorInt int brightColor) {
2994fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        setOrbColors(new Colors(color, brightColor, Color.TRANSPARENT));
3004cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    }
301731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout
302937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    /**
303937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     * Returns the orb color
304937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     * @return the RGBA color
305937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet     */
30670acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    @ColorInt
307731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    public int getOrbColor() {
3084fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        return mColors.color;
3094fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    }
3104fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
3114fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    /**
312a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the {@link Colors} used to display the search orb.
3134fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     */
3144fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    public void setOrbColors(Colors colors) {
3154fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        mColors = colors;
3164fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        mIcon.setColorFilter(mColors.iconColor);
3174fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
3184fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        if (mColorAnimator == null) {
3194fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            setOrbViewColor(mColors.color);
3204fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        } else {
3214fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            enableOrbColorAnimation(true);
3224fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        }
323731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    }
324937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet
3254fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    /**
3264fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Returns the {@link Colors} used to display the search orb.
3274fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     */
3284fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    public Colors getOrbColors() {
3294fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        return mColors;
330937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    }
331937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet
332d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout    /**
333d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout     * Enables or disables the orb color animation.
334c4788eac909f51e73e05885314d3ace65d0a2f26bulic     *
335d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout     * <p>
336d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout     * Orb color animation is handled automatically when the orb is focused/unfocused,
337d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout     * however, an app may choose to override the current animation state, for example
338d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout     * when an activity is paused.
339d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout     * </p>
340d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout     */
341d5dff7f2ff07d060e052083f1e4d9d01c2b7ee8eCraig Stout    public void enableOrbColorAnimation(boolean enable) {
34277b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        mColorAnimationEnabled = enable;
34377b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        updateColorAnimator();
34477b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov    }
34577b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov
34677b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov    private void updateColorAnimator() {
347937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        if (mColorAnimator != null) {
348937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            mColorAnimator.end();
349937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            mColorAnimator = null;
350937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        }
35177b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        if (mColorAnimationEnabled && mAttachedToWindow) {
352937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            // TODO: set interpolator (material if available)
353937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            mColorAnimator = ValueAnimator.ofObject(mColorEvaluator,
3544fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout                    mColors.color, mColors.brightColor, mColors.color);
355937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            mColorAnimator.setRepeatCount(ValueAnimator.INFINITE);
356937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            mColorAnimator.setDuration(mPulseDurationMs * 2);
357937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            mColorAnimator.addUpdateListener(mUpdateListener);
358937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            mColorAnimator.start();
359937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        }
360937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    }
361937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet
362937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    private void setOrbViewColor(int color) {
363937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        if (mSearchOrbView.getBackground() instanceof GradientDrawable) {
364937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet            ((GradientDrawable) mSearchOrbView.getBackground()).setColor(color);
365937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet        }
366937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet    }
367937f910ceb3364a1b84899c2b5f1ff5384f38f84Jerome Poichet
3686ced181ce948d1ae03c1a8402cf5ca31e2bef170Craig Stout    @Override
36977b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov    protected void onAttachedToWindow() {
37077b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        super.onAttachedToWindow();
37177b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        mAttachedToWindow = true;
37277b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        updateColorAnimator();
37377b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov    }
37477b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov
37577b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov    @Override
3766ced181ce948d1ae03c1a8402cf5ca31e2bef170Craig Stout    protected void onDetachedFromWindow() {
37777b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        mAttachedToWindow = false;
3786ced181ce948d1ae03c1a8402cf5ca31e2bef170Craig Stout        // Must stop infinite animation to prevent activity leak
37977b750bc2094fbe921058d8748fe26f830fbc6c8Dmitri Plotnikov        updateColorAnimator();
3806ced181ce948d1ae03c1a8402cf5ca31e2bef170Craig Stout        super.onDetachedFromWindow();
3816ced181ce948d1ae03c1a8402cf5ca31e2bef170Craig Stout    }
382e2679e4ccab0ce75f701629c22c179165df4f15eJerome Poichet}
383