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
17package com.android.tv.menu;
18
19import android.content.Context;
20import android.graphics.Bitmap;
21import android.support.annotation.Nullable;
22import android.text.TextUtils;
23import android.util.AttributeSet;
24import android.util.Log;
25import android.view.View;
26import android.view.ViewGroup;
27import android.widget.ImageView;
28import android.widget.ProgressBar;
29import android.widget.TextView;
30
31import com.android.tv.MainActivity;
32import com.android.tv.R;
33import com.android.tv.data.Channel;
34import com.android.tv.data.Program;
35import com.android.tv.parental.ParentalControlSettings;
36import com.android.tv.util.ImageLoader;
37
38/**
39 * A view to render channel card.
40 */
41public class ChannelCardView extends BaseCardView<Channel> {
42    private static final String TAG = MenuView.TAG;
43    private static final boolean DEBUG = MenuView.DEBUG;
44
45    private final float mCardHeight;
46    private final float mExtendedCardHeight;
47    private final float mProgramNameViewHeight;
48    private final float mExtendedTextViewCardHeight;
49    private final int mCardImageWidth;
50    private final int mCardImageHeight;
51
52    private ImageView mImageView;
53    private View mGradientView;
54    private TextView mChannelNumberNameView;
55    private ProgressBar mProgressBar;
56    private TextView mMetaViewFocused;
57    private TextView mMetaViewUnfocused;
58    private Channel mChannel;
59    private Program mProgram;
60    private boolean mExtendViewOnFocus;
61    private final MainActivity mMainActivity;
62
63    public ChannelCardView(Context context) {
64        this(context, null);
65    }
66
67    public ChannelCardView(Context context, AttributeSet attrs) {
68        this(context, attrs, 0);
69    }
70
71    public ChannelCardView(Context context, AttributeSet attrs, int defStyle) {
72        super(context, attrs, defStyle);
73
74        mCardImageWidth = getResources().getDimensionPixelSize(R.dimen.card_image_layout_width);
75        mCardImageHeight = getResources().getDimensionPixelSize(R.dimen.card_image_layout_height);
76        mCardHeight = getResources().getDimensionPixelSize(R.dimen.card_layout_height);
77        mExtendedCardHeight = getResources().getDimensionPixelSize(
78                R.dimen.card_layout_height_extended);
79        mProgramNameViewHeight = getResources().getDimensionPixelSize(
80                R.dimen.card_meta_layout_height);
81        mExtendedTextViewCardHeight = getResources().getDimensionPixelOffset(
82                R.dimen.card_meta_layout_height_extended);
83
84        mMainActivity = (MainActivity) context;
85    }
86
87    @Override
88    protected void onFinishInflate() {
89        super.onFinishInflate();
90        mImageView = (ImageView) findViewById(R.id.image);
91        mGradientView = findViewById(R.id.image_gradient);
92        mChannelNumberNameView = (TextView) findViewById(R.id.channel_number_and_name);
93        mMetaViewFocused = (TextView) findViewById(R.id.channel_title_focused);
94        mMetaViewUnfocused = (TextView) findViewById(R.id.channel_title_unfocused);
95        mProgressBar = (ProgressBar) findViewById(R.id.progress);
96    }
97
98    @Override
99    public void onBind(Channel channel, boolean selected) {
100        if (DEBUG) {
101            Log.d(TAG, "onBind(channelName=" + channel.getDisplayName() + ", selected=" + selected
102                    + ")");
103        }
104        mChannel = channel;
105        mProgram = null;
106        if (TextUtils.isEmpty(mChannel.getDisplayName())) {
107            mChannelNumberNameView.setText(mChannel.getDisplayNumber());
108        } else {
109            mChannelNumberNameView.setText(mChannel.getDisplayNumber() + " "
110                    + mChannel.getDisplayName());
111        }
112        mChannelNumberNameView.setVisibility(VISIBLE);
113        mImageView.setImageResource(R.drawable.ic_recent_thumbnail_default);
114        mImageView.setBackgroundResource(R.color.channel_card);
115        mGradientView.setVisibility(View.GONE);
116        mProgressBar.setVisibility(GONE);
117
118        setMetaViewEnabled(true);
119        if (mMainActivity.getParentalControlSettings().isParentalControlsEnabled()
120                && mChannel.isLocked()) {
121            setMetaViewText(R.string.program_title_for_blocked_channel);
122            return;
123        } else {
124            setMetaViewText("");
125        }
126
127        updateProgramInformation();
128        mMetaViewFocused.measure(
129                MeasureSpec.makeMeasureSpec(mCardImageWidth, MeasureSpec.EXACTLY),
130                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
131        if (mExtendViewOnFocus = mMetaViewFocused.getLineCount() > 1) {
132            setMetaViewFocusedAlpha(selected ? 1f : 0f);
133        } else {
134            setMetaViewFocusedAlpha(1f);
135        }
136
137        // Call super.onBind() at the end in order to make getCardHeight() return a proper value.
138        super.onBind(channel, selected);
139    }
140
141    private static ImageLoader.ImageLoaderCallback<ChannelCardView> createProgramPosterArtCallback(
142            ChannelCardView cardView, final Program program) {
143        return new ImageLoader.ImageLoaderCallback<ChannelCardView>(cardView) {
144            @Override
145            public void onBitmapLoaded(ChannelCardView cardView, @Nullable Bitmap posterArt) {
146                if (posterArt == null || cardView.mProgram == null
147                        || program.getChannelId() != cardView.mProgram.getChannelId()
148                        || program.getChannelId() != cardView.mChannel.getId()) {
149                    return;
150                }
151                cardView.updatePosterArt(posterArt);
152            }
153        };
154    }
155
156    private void updatePosterArt(Bitmap posterArt) {
157        mImageView.setImageBitmap(posterArt);
158        mGradientView.setVisibility(View.VISIBLE);
159    }
160
161    @Override
162    protected void onFocusAnimationStart(boolean selected) {
163        if (mExtendViewOnFocus) {
164            setMetaViewFocusedAlpha(selected ? 1f : 0f);
165        }
166    }
167
168    @Override
169    protected void onSetFocusAnimatedValue(float animatedValue) {
170        super.onSetFocusAnimatedValue(animatedValue);
171        if (mExtendViewOnFocus) {
172            ViewGroup.LayoutParams params = mMetaViewUnfocused.getLayoutParams();
173            params.height = Math.round(mProgramNameViewHeight
174                    + (mExtendedTextViewCardHeight - mProgramNameViewHeight) * animatedValue);
175            setMetaViewLayoutParams(params);
176            setMetaViewFocusedAlpha(animatedValue);
177        }
178    }
179
180    @Override
181    protected float getCardHeight() {
182        return (mExtendViewOnFocus && isFocused()) ? mExtendedCardHeight : mCardHeight;
183    }
184
185    private void updateProgramInformation() {
186        if (mChannel == null) {
187            return;
188        }
189        mProgram = mMainActivity.getProgramDataManager().getCurrentProgram(mChannel.getId());
190        if (mProgram == null || TextUtils.isEmpty(mProgram.getTitle())) {
191            setMetaViewEnabled(false);
192            setMetaViewText(R.string.program_title_for_no_information);
193        } else {
194            setMetaViewText(mProgram.getTitle());
195        }
196
197        if (mProgram == null) {
198            return;
199        }
200
201        long startTime = mProgram.getStartTimeUtcMillis();
202        long endTime = mProgram.getEndTimeUtcMillis();
203        long currTime = System.currentTimeMillis();
204        mProgressBar.setVisibility(View.VISIBLE);
205        if (currTime <= startTime) {
206            mProgressBar.setProgress(0);
207        } else if (currTime >= endTime) {
208            mProgressBar.setProgress(100);
209        } else {
210            mProgressBar.setProgress((int) (100 * (currTime - startTime) / (endTime - startTime)));
211        }
212
213        if (!(getContext() instanceof MainActivity)) {
214            Log.e(TAG, "Fails to check program's content rating.");
215            return;
216        }
217        ParentalControlSettings parental = mMainActivity.getParentalControlSettings();
218        if ((!parental.isParentalControlsEnabled()
219                || !parental.isRatingBlocked(mProgram.getContentRatings()))
220                && !TextUtils.isEmpty(mProgram.getPosterArtUri())) {
221            mProgram.loadPosterArt(getContext(), mCardImageWidth, mCardImageHeight,
222                    createProgramPosterArtCallback(this, mProgram));
223        }
224    }
225
226    private void setMetaViewLayoutParams(ViewGroup.LayoutParams params) {
227        mMetaViewFocused.setLayoutParams(params);
228        mMetaViewUnfocused.setLayoutParams(params);
229    }
230
231    private void setMetaViewText(String text) {
232        mMetaViewFocused.setText(text);
233        mMetaViewUnfocused.setText(text);
234    }
235
236    private void setMetaViewText(int resId) {
237        mMetaViewFocused.setText(resId);
238        mMetaViewUnfocused.setText(resId);
239    }
240
241    private void setMetaViewEnabled(boolean enabled) {
242        mMetaViewFocused.setEnabled(enabled);
243        mMetaViewUnfocused.setEnabled(enabled);
244    }
245
246    private void setMetaViewFocusedAlpha(float focusedAlpha) {
247        mMetaViewFocused.setAlpha(focusedAlpha);
248        mMetaViewUnfocused.setAlpha(1f - focusedAlpha);
249    }
250}
251