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