AppLinkCardView.java revision d41f0075a7d2ea826204e81fcec57d0aa57171a9
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.annotation.Nullable; 28import android.support.v7.graphics.Palette; 29import android.text.TextUtils; 30import android.util.AttributeSet; 31import android.util.Log; 32import android.view.View; 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.ImageLoader; 41import com.android.tv.util.TvInputManagerHelper; 42 43/** 44 * A view to render an app link card. 45 */ 46public class AppLinkCardView extends BaseCardView<Channel> { 47 private static final String TAG = MenuView.TAG; 48 private static final boolean DEBUG = MenuView.DEBUG; 49 50 private final int mCardImageWidth; 51 private final int mCardImageHeight; 52 private final int mIconWidth; 53 private final int mIconHeight; 54 private final int mIconPadding; 55 private final int mIconColorFilter; 56 57 private ImageView mImageView; 58 private View mGradientView; 59 private TextView mAppInfoView; 60 private View mMetaViewHolder; 61 private Channel mChannel; 62 private Intent mIntent; 63 private final PackageManager mPackageManager; 64 private final TvInputManagerHelper mTvInputManagerHelper; 65 66 public AppLinkCardView(Context context) { 67 this(context, null); 68 } 69 70 public AppLinkCardView(Context context, AttributeSet attrs) { 71 this(context, attrs, 0); 72 } 73 74 public AppLinkCardView(Context context, AttributeSet attrs, int defStyle) { 75 super(context, attrs, defStyle); 76 77 mCardImageWidth = getResources().getDimensionPixelSize(R.dimen.card_image_layout_width); 78 mCardImageHeight = getResources().getDimensionPixelSize(R.dimen.card_image_layout_height); 79 mIconWidth = getResources().getDimensionPixelSize(R.dimen.app_link_card_icon_width); 80 mIconHeight = getResources().getDimensionPixelSize(R.dimen.app_link_card_icon_height); 81 mIconPadding = getResources().getDimensionPixelOffset(R.dimen.app_link_card_icon_padding); 82 mPackageManager = context.getPackageManager(); 83 mTvInputManagerHelper = ((MainActivity) context).getTvInputManagerHelper(); 84 mIconColorFilter = getResources().getColor(R.color.app_link_card_icon_color_filter, null); 85 } 86 87 /** 88 * Returns the intent which will be started once this card is clicked. 89 */ 90 public Intent getIntent() { 91 return mIntent; 92 } 93 94 @Override 95 public void onBind(Channel channel, boolean selected) { 96 if (DEBUG) { 97 Log.d(TAG, "onBind(channelName=" + channel.getDisplayName() + ", selected=" + selected 98 + ")"); 99 } 100 mChannel = channel; 101 ApplicationInfo appInfo = mTvInputManagerHelper.getTvInputAppInfo(mChannel.getInputId()); 102 int linkType = mChannel.getAppLinkType(getContext()); 103 mIntent = mChannel.getAppLinkIntent(getContext()); 104 105 switch (linkType) { 106 case Channel.APP_LINK_TYPE_CHANNEL: 107 setText(mChannel.getAppLinkText()); 108 mAppInfoView.setVisibility(VISIBLE); 109 mGradientView.setVisibility(VISIBLE); 110 mAppInfoView.setCompoundDrawablePadding(mIconPadding); 111 mAppInfoView.setCompoundDrawables(null, null, null, null); 112 mAppInfoView.setText(mPackageManager.getApplicationLabel(appInfo)); 113 if (!TextUtils.isEmpty(mChannel.getAppLinkIconUri())) { 114 mChannel.loadBitmap(getContext(), Channel.LOAD_IMAGE_TYPE_APP_LINK_ICON, 115 mIconWidth, mIconHeight, createChannelLogoCallback(this, mChannel, 116 Channel.LOAD_IMAGE_TYPE_APP_LINK_ICON)); 117 } else if (appInfo.icon != 0) { 118 Drawable appIcon = mPackageManager.getApplicationIcon(appInfo); 119 BitmapUtils.setColorFilterToDrawable(mIconColorFilter, appIcon); 120 appIcon.setBounds(0, 0, mIconWidth, mIconHeight); 121 mAppInfoView.setCompoundDrawables(appIcon, null, null, null); 122 } 123 break; 124 case Channel.APP_LINK_TYPE_APP: 125 setText(getContext().getString( 126 R.string.channels_item_app_link_app_launcher, 127 mPackageManager.getApplicationLabel(appInfo))); 128 mAppInfoView.setVisibility(GONE); 129 mGradientView.setVisibility(GONE); 130 break; 131 default: 132 mAppInfoView.setVisibility(GONE); 133 mGradientView.setVisibility(GONE); 134 Log.d(TAG, "Should not be here."); 135 } 136 137 if (mChannel.getAppLinkColor() == 0) { 138 mMetaViewHolder.setBackgroundResource(R.color.channel_card_meta_background); 139 } else { 140 mMetaViewHolder.setBackgroundColor(mChannel.getAppLinkColor()); 141 } 142 143 if (!TextUtils.isEmpty(mChannel.getAppLinkPosterArtUri())) { 144 mImageView.setImageResource(R.drawable.ic_recent_thumbnail_default); 145 mChannel.loadBitmap(getContext(), Channel.LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART, 146 mCardImageWidth, mCardImageHeight, createChannelLogoCallback(this, mChannel, 147 Channel.LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART)); 148 } else { 149 setCardImageWithBanner(appInfo); 150 } 151 // Call super.onBind() at the end intentionally. In order to correctly handle extension of 152 // text view, text should be set before calling super.onBind. 153 super.onBind(channel, selected); 154 } 155 156 private static ImageLoader.ImageLoaderCallback<AppLinkCardView> createChannelLogoCallback( 157 AppLinkCardView cardView, final Channel channel, final int type) { 158 return new ImageLoader.ImageLoaderCallback<AppLinkCardView>(cardView) { 159 @Override 160 public void onBitmapLoaded(AppLinkCardView cardView, @Nullable Bitmap bitmap) { 161 // mChannel can be changed before the image load finished. 162 if (!cardView.mChannel.hasSameReadOnlyInfo(channel)) { 163 return; 164 } 165 cardView.updateChannelLogo(bitmap, type); 166 } 167 }; 168 } 169 170 private void updateChannelLogo(@Nullable Bitmap bitmap, int type) { 171 if (type == Channel.LOAD_IMAGE_TYPE_APP_LINK_ICON) { 172 BitmapDrawable drawable = null; 173 if (bitmap != null) { 174 drawable = new BitmapDrawable(getResources(), bitmap); 175 if (bitmap.getWidth() > bitmap.getHeight()) { 176 drawable.setBounds(0, 0, mIconWidth, 177 mIconWidth * bitmap.getHeight() / bitmap.getWidth()); 178 } else { 179 drawable.setBounds(0, 0, 180 mIconHeight * bitmap.getWidth() / bitmap.getHeight(), 181 mIconHeight); 182 } 183 } 184 BitmapUtils.setColorFilterToDrawable(mIconColorFilter, drawable); 185 mAppInfoView.setCompoundDrawables(drawable, null, null, null); 186 } else if (type == Channel.LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART) { 187 if (bitmap == null) { 188 setCardImageWithBanner( 189 mTvInputManagerHelper.getTvInputAppInfo(mChannel.getInputId())); 190 } else { 191 mImageView.setImageBitmap(bitmap); 192 if (mChannel.getAppLinkColor() == 0) { 193 extractAndSetMetaViewBackgroundColor(bitmap); 194 } 195 } 196 } 197 } 198 199 @Override 200 protected void onFinishInflate() { 201 super.onFinishInflate(); 202 mImageView = (ImageView) findViewById(R.id.image); 203 mGradientView = findViewById(R.id.image_gradient); 204 mAppInfoView = (TextView) findViewById(R.id.app_info); 205 mMetaViewHolder = findViewById(R.id.app_link_text_holder); 206 } 207 208 // Try to set the card image with following order: 209 // 1) Provided poster art image, 2) Activity banner, 3) Activity icon, 4) Application banner, 210 // 5) Application icon, and 6) default image. 211 private void setCardImageWithBanner(ApplicationInfo appInfo) { 212 Drawable banner = null; 213 if (mIntent != null) { 214 try { 215 banner = mPackageManager.getActivityBanner(mIntent); 216 if (banner == null) { 217 banner = mPackageManager.getActivityIcon(mIntent); 218 } 219 } catch (PackageManager.NameNotFoundException e) { 220 // do nothing. 221 } 222 } 223 224 if (banner == null && appInfo != null) { 225 if (appInfo.banner != 0) { 226 banner = mPackageManager.getApplicationBanner(appInfo); 227 } 228 if (banner == null && appInfo.icon != 0) { 229 banner = mPackageManager.getApplicationIcon(appInfo); 230 } 231 } 232 233 if (banner == null) { 234 mImageView.setImageResource(R.drawable.ic_recent_thumbnail_default); 235 mImageView.setBackgroundResource(R.color.channel_card); 236 } else { 237 Bitmap bitmap = 238 Bitmap.createBitmap(mCardImageWidth, mCardImageHeight, Bitmap.Config.ARGB_8888); 239 Canvas canvas = new Canvas(bitmap); 240 banner.setBounds(0, 0, mCardImageWidth, mCardImageHeight); 241 banner.draw(canvas); 242 mImageView.setImageDrawable(banner); 243 if (mChannel.getAppLinkColor() == 0) { 244 extractAndSetMetaViewBackgroundColor(bitmap); 245 } 246 } 247 } 248 249 private void extractAndSetMetaViewBackgroundColor(Bitmap bitmap) { 250 new Palette.Builder(bitmap).generate(new Palette.PaletteAsyncListener() { 251 @Override 252 public void onGenerated(Palette palette) { 253 mMetaViewHolder.setBackgroundColor(palette.getDarkVibrantColor( 254 getResources().getColor(R.color.channel_card_meta_background, null))); 255 } 256 }); 257 } 258} 259