SearchOrbView.java revision f0e71182c62bba18e9d8098941a29c4f5031ce36
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v17.leanback.widget; 18 19import android.animation.ArgbEvaluator; 20import android.animation.ValueAnimator; 21import android.content.Context; 22import android.content.res.TypedArray; 23import android.graphics.Color; 24import android.graphics.Rect; 25import android.graphics.drawable.Drawable; 26import android.graphics.drawable.GradientDrawable; 27import android.support.v17.leanback.R; 28import android.util.AttributeSet; 29import android.view.LayoutInflater; 30import android.view.View; 31import android.widget.FrameLayout; 32import android.widget.ImageView; 33 34public class SearchOrbView extends FrameLayout implements View.OnClickListener { 35 private OnClickListener mListener; 36 private View mSearchOrbView; 37 private int mSearchOrbColor, mSearchOrbColorBright; 38 private final float mFocusedZoom; 39 private final float mBrightnessAlpha; 40 private final int mPulseDurationMs; 41 private final int mScaleDownDurationMs; 42 private ValueAnimator mColorAnimator; 43 44 private final ArgbEvaluator mColorEvaluator = new ArgbEvaluator(); 45 46 private final ValueAnimator.AnimatorUpdateListener mUpdateListener = 47 new ValueAnimator.AnimatorUpdateListener() { 48 @Override 49 public void onAnimationUpdate(ValueAnimator animator) { 50 Integer color = (Integer) animator.getAnimatedValue(); 51 setOrbViewColor(color.intValue()); 52 } 53 }; 54 55 public SearchOrbView(Context context) { 56 this(context, null); 57 } 58 59 public SearchOrbView(Context context, AttributeSet attrs) { 60 this(context, attrs, R.style.Widget_Leanback_SearchOrbViewStyle); 61 } 62 63 public SearchOrbView(Context context, AttributeSet attrs, int defStyle) { 64 super(context, attrs, defStyle); 65 66 LayoutInflater inflater = (LayoutInflater) context 67 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 68 View root = inflater.inflate(R.layout.lb_search_orb, this, true); 69 mSearchOrbView = root.findViewById(R.id.search_orb); 70 71 ImageView icon = (ImageView)root.findViewById(R.id.icon); 72 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbSearchOrbView, 0, 73 defStyle); 74 Drawable img = a.getDrawable(R.styleable.lbSearchOrbView_searchOrbIcon); 75 icon.setImageDrawable(img); 76 77 int color = a.getColor(R.styleable.lbSearchOrbView_searchOrbColor, 0); 78 setOrbColor(color); 79 a.recycle(); 80 81 setFocusable(true); 82 setClipChildren(false); 83 84 mFocusedZoom = context.getResources().getFraction( 85 R.fraction.lb_search_orb_focused_zoom, 1, 1); 86 mBrightnessAlpha = context.getResources().getFraction( 87 R.fraction.lb_search_orb_brightness_alpha, 1, 1); 88 mPulseDurationMs = context.getResources().getInteger( 89 R.integer.lb_search_orb_pulse_duration_ms); 90 mScaleDownDurationMs = context.getResources().getInteger( 91 R.integer.lb_search_orb_scale_down_duration_ms); 92 93 setOnClickListener(this); 94 } 95 96 @Override 97 public void onClick(View view) { 98 if (null != mListener) { 99 mListener.onClick(view); 100 } 101 } 102 103 @Override 104 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 105 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 106 final float zoom = gainFocus ? mFocusedZoom : 1f; 107 final int duration = gainFocus ? mPulseDurationMs : mScaleDownDurationMs; 108 mSearchOrbView.animate().scaleX(zoom).scaleY(zoom).setDuration(duration).start(); 109 enableOrbColorAnimation(gainFocus); 110 } 111 112 private void enableOrbColorAnimation(boolean enable) { 113 if (mColorAnimator != null) { 114 mColorAnimator.end(); 115 mColorAnimator = null; 116 } 117 if (enable) { 118 // TODO: set interpolator (quantum if available) 119 mColorAnimator = ValueAnimator.ofObject(mColorEvaluator, 120 mSearchOrbColor, mSearchOrbColorBright, mSearchOrbColor); 121 mColorAnimator.setRepeatCount(ValueAnimator.INFINITE); 122 mColorAnimator.setDuration(mPulseDurationMs * 2); 123 mColorAnimator.addUpdateListener(mUpdateListener); 124 mColorAnimator.start(); 125 } 126 } 127 128 private void setOrbViewColor(int color) { 129 if (mSearchOrbView.getBackground() instanceof GradientDrawable) { 130 ((GradientDrawable) mSearchOrbView.getBackground()).setColor(color); 131 } 132 } 133 134 /** 135 * Set the on click listener for the orb 136 * @param listener The listener. 137 */ 138 public void setOnOrbClickedListener(OnClickListener listener) { 139 mListener = listener; 140 if (null != listener) { 141 setVisibility(View.VISIBLE); 142 } else { 143 setVisibility(View.INVISIBLE); 144 } 145 } 146 147 private int getBrightColor(int color) { 148 final float brightnessValue = 0xff * mBrightnessAlpha; 149 int red = (int)(Color.red(color) * (1 - mBrightnessAlpha) + brightnessValue); 150 int green = (int)(Color.green(color) * (1 - mBrightnessAlpha) + brightnessValue); 151 int blue = (int)(Color.blue(color) * (1 - mBrightnessAlpha) + brightnessValue); 152 int alpha = (int)(Color.alpha(color) * (1 - mBrightnessAlpha) + brightnessValue); 153 return Color.argb(alpha, red, green, blue); 154 } 155 156 public void setOrbColor(int color) { 157 mSearchOrbColor = color; 158 mSearchOrbColorBright = getBrightColor(color); 159 160 if (mColorAnimator == null) { 161 setOrbViewColor(color); 162 } else { 163 enableOrbColorAnimation(true); 164 } 165 } 166 167 public int getOrbColor() { 168 return mSearchOrbColor; 169 } 170} 171