SearchOrbView.java revision 5a59bde085588f95dc067bd1ed64a940f355343c
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.Resources; 23import android.content.res.TypedArray; 24import android.graphics.Color; 25import android.graphics.Rect; 26import android.graphics.drawable.Drawable; 27import android.graphics.drawable.GradientDrawable; 28import android.support.v17.leanback.R; 29import android.util.AttributeSet; 30import android.view.LayoutInflater; 31import android.view.View; 32import android.widget.FrameLayout; 33import android.widget.ImageView; 34 35/** 36 * <p>A widget that draws a search affordance, represented by a round background and an icon.</p> 37 * 38 * Background color and icon can be customized 39 */ 40public class SearchOrbView extends FrameLayout implements View.OnClickListener { 41 private OnClickListener mListener; 42 private View mSearchOrbView; 43 private ImageView mIcon; 44 private Drawable mIconDrawable; 45 private int mSearchOrbColor, mSearchOrbColorBright; 46 private final float mFocusedZoom; 47 private final float mBrightnessAlpha; 48 private final int mPulseDurationMs; 49 private final int mScaleDownDurationMs; 50 private ValueAnimator mColorAnimator; 51 52 private final ArgbEvaluator mColorEvaluator = new ArgbEvaluator(); 53 54 private final ValueAnimator.AnimatorUpdateListener mUpdateListener = 55 new ValueAnimator.AnimatorUpdateListener() { 56 @Override 57 public void onAnimationUpdate(ValueAnimator animator) { 58 Integer color = (Integer) animator.getAnimatedValue(); 59 setOrbViewColor(color.intValue()); 60 } 61 }; 62 63 public SearchOrbView(Context context) { 64 this(context, null); 65 } 66 67 public SearchOrbView(Context context, AttributeSet attrs) { 68 this(context, attrs, R.attr.searchOrbViewStyle); 69 } 70 71 public SearchOrbView(Context context, AttributeSet attrs, int defStyleAttr) { 72 super(context, attrs, defStyleAttr); 73 74 final Resources res = context.getResources(); 75 76 LayoutInflater inflater = (LayoutInflater) context 77 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 78 View root = inflater.inflate(R.layout.lb_search_orb, this, true); 79 mSearchOrbView = root.findViewById(R.id.search_orb); 80 mIcon = (ImageView)root.findViewById(R.id.icon); 81 82 mFocusedZoom = context.getResources().getFraction( 83 R.fraction.lb_search_orb_focused_zoom, 1, 1); 84 mBrightnessAlpha = context.getResources().getFraction( 85 R.fraction.lb_search_orb_brightness_alpha, 1, 1); 86 mPulseDurationMs = context.getResources().getInteger( 87 R.integer.lb_search_orb_pulse_duration_ms); 88 mScaleDownDurationMs = context.getResources().getInteger( 89 R.integer.lb_search_orb_scale_down_duration_ms); 90 91 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbSearchOrbView, 92 defStyleAttr, 0); 93 94 Drawable img = a.getDrawable(R.styleable.lbSearchOrbView_searchOrbIcon); 95 if (img == null) { 96 img = res.getDrawable(R.drawable.lb_ic_in_app_search); 97 } 98 setOrbIcon(img); 99 100 int defColor = res.getColor(R.color.lb_default_search_color); 101 int color = a.getColor(R.styleable.lbSearchOrbView_searchOrbColor, defColor); 102 int brightColor = a.getColor( 103 R.styleable.lbSearchOrbView_searchOrbBrightColor, getBrightColor(color)); 104 setOrbColor(color, brightColor); 105 a.recycle(); 106 107 setFocusable(true); 108 setClipChildren(false); 109 setOnClickListener(this); 110 } 111 112 @Override 113 public void onClick(View view) { 114 if (null != mListener) { 115 mListener.onClick(view); 116 } 117 } 118 119 @Override 120 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 121 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 122 final float zoom = gainFocus ? mFocusedZoom : 1f; 123 final int duration = gainFocus ? mPulseDurationMs : mScaleDownDurationMs; 124 mSearchOrbView.animate().scaleX(zoom).scaleY(zoom).setDuration(duration).start(); 125 enableOrbColorAnimation(gainFocus); 126 } 127 128 /** 129 * Set the orb icon 130 * @param icon the drawable to be used as the icon 131 */ 132 public void setOrbIcon(Drawable icon) { 133 mIconDrawable = icon; 134 mIcon.setImageDrawable(mIconDrawable); 135 } 136 137 /** 138 * Returns the orb icon 139 * @return the drawable used as the icon 140 */ 141 public Drawable getOrbIcon() { 142 return mIconDrawable; 143 } 144 145 /** 146 * Set the on click listener for the orb 147 * @param listener The listener. 148 */ 149 public void setOnOrbClickedListener(OnClickListener listener) { 150 mListener = listener; 151 if (null != listener) { 152 setVisibility(View.VISIBLE); 153 } else { 154 setVisibility(View.INVISIBLE); 155 } 156 } 157 158 /** 159 * Set the background color of the search orb. 160 * @param color the RGBA color 161 */ 162 public void setOrbColor(int color) { 163 setOrbColor(color, getBrightColor(color)); 164 } 165 166 public void setOrbColor(int color, int brightColor) { 167 mSearchOrbColor = color; 168 mSearchOrbColorBright = brightColor; 169 170 if (mColorAnimator == null) { 171 setOrbViewColor(color); 172 } else { 173 enableOrbColorAnimation(true); 174 } 175 } 176 177 /** 178 * Returns the orb color 179 * @return the RGBA color 180 */ 181 public int getOrbColor() { 182 return mSearchOrbColor; 183 } 184 185 private int getBrightColor(int color) { 186 final float brightnessValue = 0xff * mBrightnessAlpha; 187 int red = (int)(Color.red(color) * (1 - mBrightnessAlpha) + brightnessValue); 188 int green = (int)(Color.green(color) * (1 - mBrightnessAlpha) + brightnessValue); 189 int blue = (int)(Color.blue(color) * (1 - mBrightnessAlpha) + brightnessValue); 190 int alpha = (int)(Color.alpha(color) * (1 - mBrightnessAlpha) + brightnessValue); 191 return Color.argb(alpha, red, green, blue); 192 } 193 194 private void enableOrbColorAnimation(boolean enable) { 195 if (mColorAnimator != null) { 196 mColorAnimator.end(); 197 mColorAnimator = null; 198 } 199 if (enable) { 200 // TODO: set interpolator (material if available) 201 mColorAnimator = ValueAnimator.ofObject(mColorEvaluator, 202 mSearchOrbColor, mSearchOrbColorBright, mSearchOrbColor); 203 mColorAnimator.setRepeatCount(ValueAnimator.INFINITE); 204 mColorAnimator.setDuration(mPulseDurationMs * 2); 205 mColorAnimator.addUpdateListener(mUpdateListener); 206 mColorAnimator.start(); 207 } 208 } 209 210 private void setOrbViewColor(int color) { 211 if (mSearchOrbView.getBackground() instanceof GradientDrawable) { 212 ((GradientDrawable) mSearchOrbView.getBackground()).setColor(color); 213 } 214 } 215 216} 217