1 /*
2  * Copyright (C) 2015 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 
17 package com.android.tv.ui;
18 
19 import static com.android.tv.R.animator.tvview_block_screen_fade_out;
20 
21 import android.animation.Animator;
22 import android.animation.Animator.AnimatorListener;
23 import android.animation.AnimatorInflater;
24 import android.animation.AnimatorListenerAdapter;
25 import android.content.Context;
26 import android.graphics.drawable.Drawable;
27 import android.media.tv.TvInputInfo;
28 import android.support.annotation.Nullable;
29 import android.text.TextUtils;
30 import android.util.AttributeSet;
31 import android.view.View;
32 import android.widget.FrameLayout;
33 import android.widget.ImageView;
34 import android.widget.ImageView.ScaleType;
35 import android.widget.TextView;
36 
37 import com.android.tv.R;
38 import com.android.tv.ui.TunableTvView.BlockScreenType;
39 
40 public class BlockScreenView extends FrameLayout {
41     private View mContainerView;
42     private View mImageContainer;
43     private ImageView mNormalLockIconView;
44     private ImageView mShrunkenLockIconView;
45     private View mSpace;
46     private TextView mBlockingInfoTextView;
47     private ImageView mBackgroundImageView;
48 
49     private EmptyInputStatusBlockView mEmptyInputStatusBlockView;
50 
51     private final int mSpacingNormal;
52     private final int mSpacingShrunken;
53 
54     // Animator used to fade out the whole block screen.
55     private Animator mFadeOut;
56 
57     // Animators used to fade in/out the block screen icon and info text.
58     private Animator mInfoFadeIn;
59     private Animator mInfoFadeOut;
60 
BlockScreenView(Context context)61     public BlockScreenView(Context context) {
62         this(context, null, 0);
63     }
64 
BlockScreenView(Context context, AttributeSet attrs)65     public BlockScreenView(Context context, AttributeSet attrs) {
66         this(context, attrs, 0);
67     }
68 
BlockScreenView(Context context, AttributeSet attrs, int defStyle)69     public BlockScreenView(Context context, AttributeSet attrs, int defStyle) {
70         super(context, attrs, defStyle);
71         mSpacingNormal =
72                 getResources().getDimensionPixelOffset(R.dimen.tvview_block_vertical_spacing);
73         mSpacingShrunken =
74                 getResources()
75                         .getDimensionPixelOffset(R.dimen.shrunken_tvview_block_vertical_spacing);
76     }
77 
78     @Override
onFinishInflate()79     protected void onFinishInflate() {
80         super.onFinishInflate();
81         mContainerView = findViewById(R.id.block_screen_container);
82         mImageContainer = findViewById(R.id.image_container);
83         mNormalLockIconView = (ImageView) findViewById(R.id.block_screen_icon);
84         mShrunkenLockIconView = (ImageView) findViewById(R.id.block_screen_shrunken_icon);
85         mSpace = findViewById(R.id.space);
86         mBlockingInfoTextView = (TextView) findViewById(R.id.block_screen_text);
87         mBackgroundImageView = (ImageView) findViewById(R.id.background_image);
88         mEmptyInputStatusBlockView = findViewById(R.id.empty_input_status_block_view);
89         mFadeOut =
90                 AnimatorInflater.loadAnimator(
91                         getContext(), R.animator.tvview_block_screen_fade_out);
92         mFadeOut.setTarget(this);
93         mFadeOut.addListener(
94                 new AnimatorListenerAdapter() {
95                     @Override
96                     public void onAnimationEnd(Animator animation) {
97                         setVisibility(GONE);
98                         setBackgroundImage(null);
99                         setAlpha(1.0f);
100                     }
101                 });
102         mInfoFadeIn =
103                 AnimatorInflater.loadAnimator(getContext(), R.animator.tvview_block_screen_fade_in);
104         mInfoFadeIn.setTarget(mContainerView);
105         mInfoFadeOut =
106                 AnimatorInflater.loadAnimator(
107                         getContext(), R.animator.tvview_block_screen_fade_out);
108         mInfoFadeOut.setTarget(mContainerView);
109         mInfoFadeOut.addListener(
110                 new AnimatorListenerAdapter() {
111                     @Override
112                     public void onAnimationEnd(Animator animation) {
113                         mContainerView.setVisibility(GONE);
114                     }
115                 });
116     }
117 
118     /** Sets the normal image. */
setIconImage(int resId)119     public void setIconImage(int resId) {
120         mNormalLockIconView.setImageResource(resId);
121         updateSpaceVisibility();
122     }
123 
124     /** Sets the scale type of the normal image. */
setIconScaleType(ScaleType scaleType)125     public void setIconScaleType(ScaleType scaleType) {
126         mNormalLockIconView.setScaleType(scaleType);
127         updateSpaceVisibility();
128     }
129 
130     /** Show or hide the image of this view. */
setIconVisibility(boolean visible)131     public void setIconVisibility(boolean visible) {
132         mImageContainer.setVisibility(visible ? VISIBLE : GONE);
133         updateSpaceVisibility();
134     }
135 
136     /** Sets the text message. */
setInfoText(int resId)137     public void setInfoText(int resId) {
138         mBlockingInfoTextView.setText(resId);
139         updateSpaceVisibility();
140     }
141 
142     /** Sets the text message. */
setInfoText(String text)143     public void setInfoText(String text) {
144         mBlockingInfoTextView.setText(text);
145         updateSpaceVisibility();
146     }
147 
148     /**
149      * Sets the background image should be displayed in the block screen view. Passes {@code null}
150      * to remove the currently displayed background image.
151      */
setBackgroundImage(Drawable backgroundImage)152     public void setBackgroundImage(Drawable backgroundImage) {
153         mBackgroundImageView.setVisibility(backgroundImage == null ? GONE : VISIBLE);
154         mBackgroundImageView.setImageDrawable(backgroundImage);
155     }
156 
updateSpaceVisibility()157     private void updateSpaceVisibility() {
158         if (isImageViewVisible() && isTextViewVisible(mBlockingInfoTextView)) {
159             mSpace.setVisibility(VISIBLE);
160         } else {
161             mSpace.setVisibility(GONE);
162         }
163     }
164 
isImageViewVisible()165     private boolean isImageViewVisible() {
166         return mImageContainer.getVisibility() == VISIBLE
167                 && (isImageViewVisible(mNormalLockIconView)
168                         || isImageViewVisible(mShrunkenLockIconView));
169     }
170 
isImageViewVisible(ImageView imageView)171     private static boolean isImageViewVisible(ImageView imageView) {
172         return imageView.getVisibility() != GONE && imageView.getDrawable() != null;
173     }
174 
isTextViewVisible(TextView textView)175     private static boolean isTextViewVisible(TextView textView) {
176         return textView.getVisibility() != GONE && !TextUtils.isEmpty(textView.getText());
177     }
178 
179     /**
180      * Changes the spacing between the image view and the text view according to the {@code
181      * blockScreenType}.
182      */
setSpacing(@lockScreenType int blockScreenType)183     public void setSpacing(@BlockScreenType int blockScreenType) {
184         mSpace.getLayoutParams().height =
185                 blockScreenType == TunableTvView.BLOCK_SCREEN_TYPE_SHRUNKEN_TV_VIEW
186                         ? mSpacingShrunken
187                         : mSpacingNormal;
188         requestLayout();
189     }
190 
setInfoTextOnClickListener(@ullable OnClickListener onClickListener)191     public void setInfoTextOnClickListener(@Nullable OnClickListener onClickListener) {
192         mBlockingInfoTextView.setOnClickListener(onClickListener);
193     }
194 
195     /** Changes the view layout according to the {@code blockScreenType}. */
onBlockStatusChanged(@lockScreenType int blockScreenType, boolean withAnimation)196     public void onBlockStatusChanged(@BlockScreenType int blockScreenType, boolean withAnimation) {
197         if (!withAnimation) {
198             switch (blockScreenType) {
199                 case TunableTvView.BLOCK_SCREEN_TYPE_NO_UI:
200                     mContainerView.setVisibility(GONE);
201                     break;
202                 case TunableTvView.BLOCK_SCREEN_TYPE_SHRUNKEN_TV_VIEW:
203                     mNormalLockIconView.setVisibility(GONE);
204                     mShrunkenLockIconView.setVisibility(VISIBLE);
205                     mContainerView.setVisibility(VISIBLE);
206                     mContainerView.setAlpha(1.0f);
207                     break;
208                 case TunableTvView.BLOCK_SCREEN_TYPE_NORMAL:
209                     mNormalLockIconView.setVisibility(VISIBLE);
210                     mShrunkenLockIconView.setVisibility(GONE);
211                     mContainerView.setVisibility(VISIBLE);
212                     mContainerView.setAlpha(1.0f);
213                     break;
214             }
215         } else {
216             switch (blockScreenType) {
217                 case TunableTvView.BLOCK_SCREEN_TYPE_NO_UI:
218                     if (mContainerView.getVisibility() == VISIBLE) {
219                         mInfoFadeOut.start();
220                     }
221                     break;
222                 case TunableTvView.BLOCK_SCREEN_TYPE_SHRUNKEN_TV_VIEW:
223                     mNormalLockIconView.setVisibility(GONE);
224                     mShrunkenLockIconView.setVisibility(VISIBLE);
225                     if (mContainerView.getVisibility() == GONE) {
226                         mContainerView.setVisibility(VISIBLE);
227                         mInfoFadeIn.start();
228                     }
229                     break;
230                 case TunableTvView.BLOCK_SCREEN_TYPE_NORMAL:
231                     mNormalLockIconView.setVisibility(VISIBLE);
232                     mShrunkenLockIconView.setVisibility(GONE);
233                     if (mContainerView.getVisibility() == GONE) {
234                         mContainerView.setVisibility(VISIBLE);
235                         mInfoFadeIn.start();
236                     }
237                     break;
238             }
239         }
240         updateSpaceVisibility();
241     }
242 
243     /** Adds a listener to the fade-in animation of info text and icons of the block screen. */
addInfoFadeInAnimationListener(AnimatorListener listener)244     public void addInfoFadeInAnimationListener(AnimatorListener listener) {
245         mInfoFadeIn.addListener(listener);
246     }
247 
248     /** Fades out the block screen. */
fadeOut()249     public void fadeOut() {
250         if (getVisibility() == VISIBLE && !mFadeOut.isStarted()) {
251             mFadeOut.start();
252         }
253     }
254 
255     /** Ends the currently running animations. */
endAnimations()256     public void endAnimations() {
257         if (mFadeOut != null && mFadeOut.isRunning()) {
258             mFadeOut.end();
259         }
260         if (mInfoFadeIn != null && mInfoFadeIn.isRunning()) {
261             mInfoFadeIn.end();
262         }
263         if (mInfoFadeOut != null && mInfoFadeOut.isRunning()) {
264             mInfoFadeOut.end();
265         }
266     }
267 
setInfoTextClickable(boolean clickable)268     public void setInfoTextClickable(boolean clickable) {
269         mBlockingInfoTextView.setClickable(clickable);
270     }
271 
setEmptyInputStatusInputInfo(TvInputInfo inputInfo)272     public void setEmptyInputStatusInputInfo(TvInputInfo inputInfo) {
273         mEmptyInputStatusBlockView.setIconAndLabelByInputInfo(inputInfo);
274     }
275 
setEmptyInputStatusBlockVisibility(boolean visible)276     public void setEmptyInputStatusBlockVisibility(boolean visible) {
277         mEmptyInputStatusBlockView.setVisibility(visible ? View.VISIBLE : View.GONE);
278     }
279 }
280