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.menu; 18 19 import android.content.Context; 20 import android.graphics.Bitmap; 21 import android.support.annotation.Nullable; 22 import android.text.TextUtils; 23 import android.util.AttributeSet; 24 import android.util.Log; 25 import android.view.View; 26 import android.view.ViewGroup; 27 import android.widget.ImageView; 28 import android.widget.ProgressBar; 29 import android.widget.TextView; 30 31 import com.android.tv.MainActivity; 32 import com.android.tv.R; 33 import com.android.tv.data.Channel; 34 import com.android.tv.data.Program; 35 import com.android.tv.parental.ParentalControlSettings; 36 import com.android.tv.util.ImageLoader; 37 38 /** 39 * A view to render channel card. 40 */ 41 public 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