Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2016 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 package com.android.car.media;
     17 
     18 import android.content.Context;
     19 import android.graphics.Bitmap;
     20 import android.graphics.Color;
     21 import android.graphics.ColorFilter;
     22 import android.graphics.ColorMatrix;
     23 import android.graphics.ColorMatrixColorFilter;
     24 import android.util.AttributeSet;
     25 import android.view.View;
     26 import android.view.ViewGroup;
     27 import android.view.animation.Animation;
     28 import android.view.animation.AnimationUtils;
     29 import android.view.animation.DecelerateInterpolator;
     30 import android.widget.FrameLayout;
     31 import android.widget.ImageView;
     32 
     33 /**
     34  * A view where updating the image will show certain animations. Current animations include fading
     35  * in and scaling down the new image.
     36  */
     37 public class CrossfadeImageView extends FrameLayout {
     38     // ColorFilters can't currently be modified (b/17262092) so creating a saturation fade with
     39     // color filters would normally require creating a ton of small objects. We get around this by
     40     // caching color filters and limit the saturation to increments of 0.1.
     41     // 0-0.09 -> [0]
     42     // 0.10-0.19 -> [1]
     43     // ...
     44     // 1.0 -> [10]
     45     private final ColorFilter[] mSaturationColorFilters = new ColorFilter[11];
     46     private final ColorMatrix mColorMatrix = new ColorMatrix();
     47     private final ImageView mImageView1;
     48     private final ImageView mImageView2;
     49 
     50     private ImageView mActiveImageView;
     51     private ImageView mInactiveImageView;
     52 
     53     private Bitmap mCurrentBitmap = null;
     54     private Integer mCurrentColor = null;
     55     private Animation mImageInAnimation;
     56     private Animation mImageOutAnimation;
     57 
     58     public CrossfadeImageView(Context context) {
     59         this(context, null);
     60     }
     61 
     62     public CrossfadeImageView(Context context, AttributeSet attrs) {
     63         this(context, attrs, 0);
     64     }
     65 
     66     public CrossfadeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
     67         this(context, attrs, defStyleAttr, 0);
     68     }
     69 
     70     public CrossfadeImageView(Context context, AttributeSet attrs,
     71             int defStyleAttr, int defStyleRes) {
     72         super(context, attrs, defStyleAttr, defStyleRes);
     73         LayoutParams lp = new LayoutParams(
     74                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
     75         ImageView imageViewBackground = new ImageView(context, attrs, defStyleAttr, defStyleRes);
     76         imageViewBackground.setLayoutParams(lp);
     77         imageViewBackground.setBackgroundColor(Color.BLACK);
     78         addView(imageViewBackground);
     79         mImageView1 = new ImageView(context, attrs, defStyleAttr, defStyleRes);
     80         mImageView1.setLayoutParams(lp);
     81         addView(mImageView1);
     82         mImageView2 = new ImageView(context, attrs, defStyleAttr, defStyleRes);
     83         mImageView2.setLayoutParams(lp);
     84         addView(mImageView2);
     85 
     86         mActiveImageView = mImageView1;
     87         mInactiveImageView = mImageView2;
     88 
     89         mImageInAnimation = AnimationUtils.loadAnimation(context, R.anim.image_in);
     90         mImageInAnimation.setInterpolator(new DecelerateInterpolator());
     91         mImageOutAnimation = AnimationUtils.loadAnimation(context, R.anim.image_out);
     92     }
     93 
     94     public void setImageBitmap(Bitmap bitmap, boolean showAnimation) {
     95         if (bitmap == null) {
     96             return;
     97         }
     98 
     99         if (mCurrentBitmap != null && bitmap.sameAs(mCurrentBitmap)) {
    100             return;
    101         }
    102 
    103         mCurrentBitmap = bitmap;
    104         mCurrentColor = null;
    105         mInactiveImageView.setImageBitmap(bitmap);
    106         if (showAnimation) {
    107             animateViews();
    108         } else {
    109             mActiveImageView.setImageBitmap(bitmap);
    110         }
    111     }
    112 
    113     @Override
    114     public void setBackgroundColor(int color) {
    115         if (mCurrentColor != null && mCurrentColor == color) {
    116             return;
    117         }
    118         mInactiveImageView.setImageBitmap(null);
    119         mCurrentBitmap = null;
    120         mCurrentColor = color;
    121         mInactiveImageView.setBackgroundColor(color);
    122         animateViews();
    123     }
    124 
    125     public void setSaturation(float saturation) {
    126         int i = (int) ((saturation * 100) / 10);
    127         ColorFilter cf = mSaturationColorFilters[i];
    128         if (cf == null) {
    129             mColorMatrix.setSaturation((10 * i) / 100f);
    130             cf = new ColorMatrixColorFilter(mColorMatrix);
    131             mSaturationColorFilters[i] = cf;
    132         }
    133 
    134         mImageView1.setColorFilter(cf);
    135         mImageView2.setColorFilter(cf);
    136     }
    137 
    138     private final Animation.AnimationListener mAnimationListener =
    139             new Animation.AnimationListener() {
    140         @Override
    141         public void onAnimationEnd(Animation animation) {
    142             if (mInactiveImageView != null) {
    143                 mInactiveImageView.setVisibility(View.GONE);
    144             }
    145         }
    146 
    147         @Override
    148         public void onAnimationStart(Animation animation) { }
    149 
    150         @Override
    151         public void onAnimationRepeat(Animation animation) { }
    152     };
    153 
    154     private void animateViews() {
    155         mInactiveImageView.setVisibility(View.VISIBLE);
    156         mInactiveImageView.startAnimation(mImageInAnimation);
    157         mInactiveImageView.bringToFront();
    158         mActiveImageView.startAnimation(mImageOutAnimation);
    159         mImageOutAnimation.setAnimationListener(mAnimationListener);
    160         if (mActiveImageView == mImageView1) {
    161             mActiveImageView = mImageView2;
    162             mInactiveImageView = mImageView1;
    163         } else {
    164             mActiveImageView = mImageView1;
    165             mInactiveImageView = mImageView2;
    166         }
    167     }
    168 }
    169