AppLinkCardView.java revision 07b043dc3db83d6d20f0e8513b946830ab00e37b
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.content.Intent; 21import android.content.pm.ApplicationInfo; 22import android.content.pm.PackageManager; 23import android.graphics.Bitmap; 24import android.graphics.Canvas; 25import android.graphics.drawable.BitmapDrawable; 26import android.graphics.drawable.Drawable; 27import android.support.v7.graphics.Palette; 28import android.text.TextUtils; 29import android.util.AttributeSet; 30import android.util.Log; 31import android.view.View; 32import android.view.ViewGroup; 33import android.widget.ImageView; 34import android.widget.TextView; 35 36import com.android.tv.MainActivity; 37import com.android.tv.R; 38import com.android.tv.data.Channel; 39import com.android.tv.util.BitmapUtils; 40import com.android.tv.util.TvInputManagerHelper; 41 42/** 43 * A view to render an app link card. 44 */ 45public class AppLinkCardView extends BaseCardView<Channel> implements Channel.LoadImageCallback { 46 private static final String TAG = MenuView.TAG; 47 private static final boolean DEBUG = MenuView.DEBUG; 48 49 private final float mCardHeight; 50 private final float mExtendedCardHeight; 51 private final float mTextViewHeight; 52 private final float mExtendedTextViewCardHeight; 53 private final int mCardImageWidth; 54 private final int mCardImageHeight; 55 private final int mIconWidth; 56 private final int mIconHeight; 57 private final int mIconPadding; 58 private final int mIconColorFilter; 59 60 private ImageView mImageView; 61 private View mGradientView; 62 private TextView mAppInfoView; 63 private TextView mMetaViewFocused; 64 private TextView mMetaViewUnfocused; 65 private View mMetaViewHolder; 66 private Channel mChannel; 67 private Intent mIntent; 68 private boolean mExtendViewOnFocus; 69 private final PackageManager mPackageManager; 70 private final TvInputManagerHelper mTvInputManagerHelper; 71 72 public AppLinkCardView(Context context) { 73 this(context, null); 74 } 75 76 public AppLinkCardView(Context context, AttributeSet attrs) { 77 this(context, attrs, 0); 78 } 79 80 public AppLinkCardView(Context context, AttributeSet attrs, int defStyle) { 81 super(context, attrs, defStyle); 82 83 mCardImageWidth = getResources().getDimensionPixelSize(R.dimen.card_image_layout_width); 84 mCardImageHeight = getResources().getDimensionPixelSize(R.dimen.card_image_layout_height); 85 mCardHeight = getResources().getDimensionPixelSize(R.dimen.card_layout_height); 86 mExtendedCardHeight = getResources().getDimensionPixelOffset( 87 R.dimen.card_layout_height_extended); 88 mIconWidth = getResources().getDimensionPixelSize(R.dimen.app_link_card_icon_width); 89 mIconHeight = getResources().getDimensionPixelSize(R.dimen.app_link_card_icon_height); 90 mIconPadding = getResources().getDimensionPixelOffset(R.dimen.app_link_card_icon_padding); 91 mPackageManager = context.getPackageManager(); 92 mTvInputManagerHelper = ((MainActivity) context).getTvInputManagerHelper(); 93 mTextViewHeight = getResources().getDimensionPixelSize( 94 R.dimen.card_meta_layout_height); 95 mExtendedTextViewCardHeight = getResources().getDimensionPixelOffset( 96 R.dimen.card_meta_layout_height_extended); 97 mIconColorFilter = getResources().getColor(R.color.app_link_card_icon_color_filter, null); 98 } 99 100 /** 101 * Returns the intent which will be started once this card is clicked. 102 */ 103 public Intent getIntent() { 104 return mIntent; 105 } 106 107 @Override 108 public void onBind(Channel channel, boolean selected) { 109 if (DEBUG) { 110 Log.d(TAG, "onBind(channel=" + channel.getDisplayName() + ", selected=" + selected 111 + ")"); 112 } 113 mChannel = channel; 114 ApplicationInfo appInfo = mTvInputManagerHelper.getTvInputAppInfo(mChannel.getInputId()); 115 int linkType = mChannel.getAppLinkType(getContext()); 116 mIntent = mChannel.getAppLinkIntent(getContext()); 117 118 switch (linkType) { 119 case Channel.APP_LINK_TYPE_CHANNEL: 120 setMetaViewText(mChannel.getAppLinkText()); 121 mAppInfoView.setVisibility(VISIBLE); 122 mGradientView.setVisibility(VISIBLE); 123 mAppInfoView.setCompoundDrawablePadding(mIconPadding); 124 mAppInfoView.setCompoundDrawables(null, null, null, null); 125 mAppInfoView.setText(mPackageManager.getApplicationLabel(appInfo)); 126 if (!TextUtils.isEmpty(mChannel.getAppLinkIconUri())) { 127 mChannel.loadBitmap(getContext(), Channel.LOAD_IMAGE_TYPE_APP_LINK_ICON, 128 mIconWidth, mIconHeight, this); 129 } else if (appInfo.icon != 0) { 130 Drawable appIcon = mPackageManager.getApplicationIcon(appInfo); 131 BitmapUtils.setColorFilterToDrawable(mIconColorFilter, appIcon); 132 appIcon.setBounds(0, 0, mIconWidth, mIconHeight); 133 mAppInfoView.setCompoundDrawables(appIcon, null, null, null); 134 } 135 break; 136 case Channel.APP_LINK_TYPE_APP: 137 setMetaViewText(getContext().getString( 138 R.string.channels_item_app_link_app_launcher, 139 mPackageManager.getApplicationLabel(appInfo))); 140 mAppInfoView.setVisibility(GONE); 141 mGradientView.setVisibility(GONE); 142 break; 143 default: 144 mAppInfoView.setVisibility(GONE); 145 mGradientView.setVisibility(GONE); 146 Log.d(TAG, "Should not be here."); 147 } 148 149 if (mChannel.getAppLinkColor() == 0) { 150 mMetaViewHolder.setBackgroundResource(R.color.channel_card_meta_background); 151 } else { 152 mMetaViewHolder.setBackgroundColor(mChannel.getAppLinkColor()); 153 } 154 155 if (!TextUtils.isEmpty(mChannel.getAppLinkPosterArtUri())) { 156 mImageView.setImageResource(R.drawable.ic_recent_thumbnail_default); 157 mChannel.loadBitmap(getContext(), Channel.LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART, 158 mCardImageWidth, mCardImageHeight, this); 159 } else { 160 setCardImageWithBanner(appInfo); 161 } 162 163 mMetaViewFocused.measure(MeasureSpec.makeMeasureSpec(mCardImageWidth, MeasureSpec.EXACTLY), 164 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 165 mExtendViewOnFocus = mMetaViewFocused.getLineCount() > 1; 166 if (mExtendViewOnFocus) { 167 setMetaViewFocusedAlpha(selected ? 1f : 0f); 168 } else { 169 setMetaViewFocusedAlpha(1f); 170 } 171 172 // Call super.onBind() at the end in order to make getCardHeight() return a proper value. 173 super.onBind(channel, selected); 174 } 175 176 @Override 177 public void onLoadImageFinished(Channel channel, int type, Bitmap bitmap) { 178 // mChannel can be changed before the image load finished. 179 if (!mChannel.hasSameReadOnlyInfo(channel)) { 180 return; 181 } 182 if (type == Channel.LOAD_IMAGE_TYPE_APP_LINK_ICON) { 183 BitmapDrawable drawable = null; 184 if (bitmap != null) { 185 drawable = new BitmapDrawable(getResources(), bitmap); 186 if (bitmap.getWidth() > bitmap.getHeight()) { 187 drawable.setBounds(0, 0, mIconWidth, 188 mIconWidth * bitmap.getHeight() / bitmap.getWidth()); 189 } else { 190 drawable.setBounds(0, 0, mIconHeight * bitmap.getWidth() / bitmap.getHeight(), 191 mIconHeight); 192 } 193 } 194 BitmapUtils.setColorFilterToDrawable(mIconColorFilter, drawable); 195 mAppInfoView.setCompoundDrawables(drawable, null, null, null); 196 } else if (type == Channel.LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART) { 197 if (bitmap == null) { 198 setCardImageWithBanner( 199 mTvInputManagerHelper.getTvInputAppInfo(mChannel.getInputId())); 200 } else { 201 mImageView.setImageBitmap(bitmap); 202 if (mChannel.getAppLinkColor() == 0) { 203 extractAndSetMetaViewBackgroundColor(bitmap); 204 } 205 } 206 } 207 } 208 209 @Override 210 protected void onFinishInflate() { 211 mImageView = (ImageView) findViewById(R.id.image); 212 mGradientView = findViewById(R.id.image_gradient); 213 mAppInfoView = (TextView) findViewById(R.id.app_info); 214 mMetaViewHolder = findViewById(R.id.app_link_text_holder); 215 mMetaViewFocused = (TextView) findViewById(R.id.app_link_text_focused); 216 mMetaViewUnfocused = (TextView) findViewById(R.id.app_link_text_unfocused); 217 } 218 219 @Override 220 protected void onFocusAnimationStart(boolean selected) { 221 if (mExtendViewOnFocus) { 222 setMetaViewFocusedAlpha(selected ? 1f : 0f); 223 } 224 } 225 226 @Override 227 protected void onSetFocusAnimatedValue(float animatedValue) { 228 super.onSetFocusAnimatedValue(animatedValue); 229 if (mExtendViewOnFocus) { 230 ViewGroup.LayoutParams params = mMetaViewUnfocused.getLayoutParams(); 231 params.height = Math.round(mTextViewHeight 232 + (mExtendedTextViewCardHeight - mTextViewHeight) * animatedValue); 233 setMetaViewLayoutParams(params); 234 setMetaViewFocusedAlpha(animatedValue); 235 } 236 } 237 238 @Override 239 protected float getCardHeight() { 240 return (mExtendViewOnFocus && isFocused()) ? mExtendedCardHeight : mCardHeight; 241 } 242 243 // Try to set the card image with following order: 244 // 1) Provided poster art image, 2) Activity banner, 3) Application banner, 245 // 4) Activity logo, 5) Application logo, and 6) default image. 246 private void setCardImageWithBanner(ApplicationInfo appInfo) { 247 Drawable banner = null; 248 try { 249 banner = mPackageManager.getActivityBanner(mIntent); 250 } catch (PackageManager.NameNotFoundException e) { 251 // do nothing. 252 } 253 if (banner == null && appInfo != null && appInfo.banner != 0) { 254 banner = mPackageManager.getApplicationBanner(appInfo); 255 } 256 if (banner == null) { 257 try { 258 banner = mPackageManager.getActivityLogo(mIntent); 259 } catch (PackageManager.NameNotFoundException e) { 260 // do nothing. 261 } 262 } 263 if (banner == null && appInfo != null && appInfo.logo != 0) { 264 banner = mPackageManager.getApplicationLogo(appInfo); 265 } 266 267 if (banner == null) { 268 mImageView.setImageResource(R.drawable.ic_recent_thumbnail_default); 269 mImageView.setBackgroundResource(R.color.channel_card); 270 } else { 271 Bitmap bitmap = 272 Bitmap.createBitmap(mCardImageWidth, mCardImageHeight, Bitmap.Config.ARGB_8888); 273 Canvas canvas = new Canvas(bitmap); 274 banner.setBounds(0, 0, mCardImageWidth, mCardImageHeight); 275 banner.draw(canvas); 276 mImageView.setImageDrawable(banner); 277 if (mChannel.getAppLinkColor() == 0) { 278 extractAndSetMetaViewBackgroundColor(bitmap); 279 } 280 } 281 } 282 283 private void extractAndSetMetaViewBackgroundColor(Bitmap bitmap) { 284 new Palette.Builder(bitmap).generate(new Palette.PaletteAsyncListener() { 285 @Override 286 public void onGenerated(Palette palette) { 287 mMetaViewHolder.setBackgroundColor(palette.getDarkVibrantColor( 288 getResources().getColor(R.color.channel_card_meta_background, null))); 289 } 290 }); 291 } 292 293 private void setMetaViewLayoutParams(ViewGroup.LayoutParams params) { 294 mMetaViewFocused.setLayoutParams(params); 295 mMetaViewUnfocused.setLayoutParams(params); 296 } 297 298 private void setMetaViewText(String text) { 299 mMetaViewFocused.setText(text); 300 mMetaViewUnfocused.setText(text); 301 } 302 303 private void setMetaViewFocusedAlpha(float focusedAlpha) { 304 mMetaViewFocused.setAlpha(focusedAlpha); 305 mMetaViewUnfocused.setAlpha(1f - focusedAlpha); 306 } 307} 308