1 /*
2  * Copyright (C) 2019 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.apps.common;
17 
18 import android.content.Context;
19 import android.content.res.TypedArray;
20 import android.graphics.Bitmap;
21 import android.graphics.drawable.BitmapDrawable;
22 import android.graphics.drawable.Drawable;
23 import android.util.AttributeSet;
24 import android.util.Size;
25 import android.view.View;
26 
27 import androidx.annotation.Nullable;
28 import androidx.constraintlayout.widget.ConstraintLayout;
29 
30 /**
31  * A View to place a large, blurred image in the background.
32  * Intended for Car's Dialer and Media apps.
33  */
34 public class BackgroundImageView extends ConstraintLayout {
35 
36     private CrossfadeImageView mImageView;
37 
38     /** Configuration (controlled from resources) */
39     private Size mBitmapTargetSize;
40     private float mBitmapBlurPercent;
41 
42     private View mDarkeningScrim;
43 
BackgroundImageView(Context context)44     public BackgroundImageView(Context context) {
45         this(context, null);
46     }
47 
BackgroundImageView(Context context, AttributeSet attrs)48     public BackgroundImageView(Context context, AttributeSet attrs) {
49         this(context, attrs, R.attr.backgroundImageViewStyle);
50     }
51 
BackgroundImageView(Context context, AttributeSet attrs, int defStyle)52     public BackgroundImageView(Context context, AttributeSet attrs, int defStyle) {
53         super(context, attrs, defStyle);
54 
55         float extraScale;
56         int resId;
57         TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
58                 R.styleable.BackgroundImageView, defStyle, 0);
59         try {
60             extraScale = a.getFloat(R.styleable.BackgroundImageView_imageAdditionalScale, 1.05f);
61             resId = a.getResourceId(R.styleable.BackgroundImageView_contentLayout,
62                     R.layout.background_image);
63             mBitmapBlurPercent = a.getFloat(R.styleable.BackgroundImageView_bitmap_blur_percent,
64                     getResources().getFloat(R.dimen.background_bitmap_blur_percent));
65 
66             int size = a.getInteger(R.styleable.BackgroundImageView_bitmap_target_size_px,
67                     getResources().getInteger(R.integer.background_bitmap_target_size_px));
68             mBitmapTargetSize = new Size(size, size);
69         } finally {
70             a.recycle();
71         }
72 
73         inflate(getContext(), resId, this);
74 
75         mImageView = findViewById(R.id.background_image_image);
76         mDarkeningScrim = findViewById(R.id.background_image_darkening_scrim);
77 
78         setImageAdditionalScale(extraScale);
79     }
80 
81     /**
82      * @deprecated Use {@link #setBackgroundDrawable} instead, and make sure to only call when the
83      * image is actually different! TODO(b/139387273).
84      * Sets the image to display to a bitmap
85      * @param bitmap The image to show. It will be scaled to the correct size and blurred.
86      * @param showAnimation Whether or not to cross fade to the new image
87      */
88     @Deprecated
setBackgroundImage(@ullable Bitmap bitmap, boolean showAnimation)89     public void setBackgroundImage(@Nullable Bitmap bitmap, boolean showAnimation) {
90         Drawable drawable = (bitmap != null) ? new BitmapDrawable(bitmap) : null;
91         updateBlur(drawable, showAnimation);
92     }
93 
94     /** Sets the drawable that will be displayed blurred by this view. */
setBackgroundDrawable(@ullable Drawable drawable)95     public void setBackgroundDrawable(@Nullable Drawable drawable) {
96         setBackgroundDrawable(drawable, true);
97     }
98 
99     /**
100      * Sets the drawable that will be displayed blurred by this view specifying if animation is
101      * enabled.
102      */
setBackgroundDrawable(@ullable Drawable drawable, boolean showAnimation)103     public void setBackgroundDrawable(@Nullable Drawable drawable, boolean showAnimation) {
104         updateBlur(drawable, showAnimation);
105     }
106 
updateBlur(@ullable Drawable drawable, boolean showAnimation)107     private void updateBlur(@Nullable Drawable drawable, boolean showAnimation) {
108         if (drawable == null) {
109             mImageView.setImageBitmap(null, false);
110             return;
111         }
112 
113         Bitmap src = BitmapUtils.fromDrawable(drawable, mBitmapTargetSize);
114         Bitmap blurred = ImageUtils.blur(getContext(), src, mBitmapTargetSize, mBitmapBlurPercent);
115         mImageView.setImageBitmap(blurred, showAnimation);
116         invalidate();
117         requestLayout();
118     }
119 
120     /** Sets the background to a color */
setBackgroundColor(int color)121     public void setBackgroundColor(int color) {
122         mImageView.setBackgroundColor(color);
123     }
124 
125     /** Dims/undims the background image by 30% */
setDimmed(boolean dim)126     public void setDimmed(boolean dim) {
127         mDarkeningScrim.setVisibility(dim ? View.VISIBLE : View.GONE);
128     }
129 
130     /**
131      * Sets a scale to be applied on top of the scaling that was used to fit the
132      * image to the frame of the view.
133      *
134      * See {@link
135      * com.android.car.apps.common.CropAlignedImageView#setImageAdditionalScale(float)}
136      * for more details.
137      */
setImageAdditionalScale(float scale)138     public void setImageAdditionalScale(float scale) {
139         mImageView.setImageAdditionalScale(scale);
140     }
141 }
142