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.content.Intent; 21 import android.media.tv.TvInputInfo; 22 import android.os.Build; 23 import android.support.v4.os.BuildCompat; 24 import android.view.View; 25 26 import com.android.tv.MainActivity; 27 import com.android.tv.R; 28 import com.android.tv.TvApplication; 29 import com.android.tv.analytics.Tracker; 30 import com.android.tv.common.feature.CommonFeatures; 31 import com.android.tv.data.Channel; 32 import com.android.tv.recommendation.Recommender; 33 import com.android.tv.util.SetupUtils; 34 import com.android.tv.util.TvInputManagerHelper; 35 import com.android.tv.util.Utils; 36 37 import java.util.ArrayList; 38 import java.util.List; 39 40 /** 41 * An adapter of the Channels row. 42 */ 43 public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel> { 44 // There are four special cards: guide, setup, dvr, record, applink. 45 private static final int SIZE_OF_VIEW_TYPE = 5; 46 47 private final Context mContext; 48 private final Tracker mTracker; 49 private final Recommender mRecommender; 50 private final int mMaxCount; 51 private final int mMinCount; 52 private final boolean mDvrFeatureEnabled; 53 private final int[] mViewType = new int[SIZE_OF_VIEW_TYPE]; 54 55 private final View.OnClickListener mGuideOnClickListener = new View.OnClickListener() { 56 @Override 57 public void onClick(View view) { 58 mTracker.sendMenuClicked(R.string.channels_item_program_guide); 59 getMainActivity().getOverlayManager().showProgramGuide(); 60 } 61 }; 62 63 private final View.OnClickListener mSetupOnClickListener = new View.OnClickListener() { 64 @Override 65 public void onClick(View view) { 66 mTracker.sendMenuClicked(R.string.channels_item_setup); 67 getMainActivity().getOverlayManager().showSetupFragment(); 68 } 69 }; 70 71 private final View.OnClickListener mDvrOnClickListener = new View.OnClickListener() { 72 @Override 73 public void onClick(View view) { 74 Utils.showToastMessageForDeveloperFeature(view.getContext()); 75 mTracker.sendMenuClicked(R.string.channels_item_dvr); 76 getMainActivity().getOverlayManager().showDvrManager(); 77 } 78 }; 79 80 private final View.OnClickListener mRecordOnClickListener = new View.OnClickListener() { 81 @Override 82 public void onClick(View view) { 83 Utils.showToastMessageForDeveloperFeature(view.getContext()); 84 RecordCardView v = ((RecordCardView) view); 85 boolean isRecording = v.isRecording(); 86 mTracker.sendMenuClicked(isRecording ? R.string.channels_item_record_start 87 : R.string.channels_item_record_stop); 88 if (!isRecording) { 89 v.startRecording(); 90 } else { 91 v.stopRecording(); 92 } 93 } 94 }; 95 96 private final View.OnClickListener mAppLinkOnClickListener = new View.OnClickListener() { 97 @Override 98 public void onClick(View view) { 99 mTracker.sendMenuClicked(R.string.channels_item_app_link); 100 Intent intent = ((AppLinkCardView) view).getIntent(); 101 if (intent != null) { 102 getMainActivity().startActivitySafe(intent); 103 } 104 } 105 }; 106 107 private final View.OnClickListener mChannelOnClickListener = new View.OnClickListener() { 108 @Override 109 public void onClick(View view) { 110 // Always send the label "Channels" because the channel ID or name or number might be 111 // sensitive. 112 mTracker.sendMenuClicked(R.string.menu_title_channels); 113 getMainActivity().tuneToChannel((Channel) view.getTag()); 114 getMainActivity().hideOverlaysForTune(); 115 } 116 }; 117 ChannelsRowAdapter(Context context, Recommender recommender, int minCount, int maxCount)118 public ChannelsRowAdapter(Context context, Recommender recommender, 119 int minCount, int maxCount) { 120 super(context); 121 mTracker = TvApplication.getSingletons(context).getTracker(); 122 mContext = context; 123 mRecommender = recommender; 124 mMinCount = minCount; 125 mMaxCount = maxCount; 126 mDvrFeatureEnabled = CommonFeatures.DVR.isEnabled(mContext) && BuildCompat.isAtLeastN(); 127 } 128 129 @Override getItemViewType(int position)130 public int getItemViewType(int position) { 131 if (position >= SIZE_OF_VIEW_TYPE) { 132 return R.layout.menu_card_channel; 133 } 134 return mViewType[position]; 135 } 136 137 @Override getLayoutResId(int viewType)138 protected int getLayoutResId(int viewType) { 139 return viewType; 140 } 141 142 @Override onBindViewHolder(MyViewHolder viewHolder, int position)143 public void onBindViewHolder(MyViewHolder viewHolder, int position) { 144 super.onBindViewHolder(viewHolder, position); 145 146 int viewType = getItemViewType(position); 147 if (viewType == R.layout.menu_card_guide) { 148 viewHolder.itemView.setOnClickListener(mGuideOnClickListener); 149 } else if (viewType == R.layout.menu_card_setup) { 150 viewHolder.itemView.setOnClickListener(mSetupOnClickListener); 151 } else if (viewType == R.layout.menu_card_app_link) { 152 viewHolder.itemView.setOnClickListener(mAppLinkOnClickListener); 153 } else if (viewType == R.layout.menu_card_dvr) { 154 viewHolder.itemView.setOnClickListener(mDvrOnClickListener); 155 } else if (viewType == R.layout.menu_card_record) { 156 viewHolder.itemView.setOnClickListener(mRecordOnClickListener); 157 } else { 158 viewHolder.itemView.setTag(getItemList().get(position)); 159 viewHolder.itemView.setOnClickListener(mChannelOnClickListener); 160 } 161 } 162 163 @Override update()164 public void update() { 165 List<Channel> channelList = new ArrayList<>(); 166 Channel dummyChannel = new Channel.Builder().build(); 167 // For guide item 168 channelList.add(dummyChannel); 169 // For setup item 170 TvInputManagerHelper inputManager = TvApplication.getSingletons(mContext) 171 .getTvInputManagerHelper(); 172 boolean showSetupCard = SetupUtils.getInstance(mContext).hasNewInput(inputManager); 173 Channel currentChannel = ((MainActivity) mContext).getCurrentChannel(); 174 boolean showAppLinkCard = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 175 && currentChannel != null 176 && currentChannel.getAppLinkType(mContext) != Channel.APP_LINK_TYPE_NONE; 177 boolean showDvrCard = false; 178 boolean showRecordCard = false; 179 if (mDvrFeatureEnabled) { 180 for (TvInputInfo info : inputManager.getTvInputInfos(true, true)) { 181 if (info.canRecord()) { 182 showDvrCard = true; 183 break; 184 } 185 } 186 if (currentChannel != null && currentChannel.getInputId() != null) { 187 TvInputInfo inputInfo = inputManager.getTvInputInfo(currentChannel.getInputId()); 188 if ((inputInfo.canRecord() && inputInfo.getTunerCount() > 1)) { 189 showRecordCard = true; 190 } 191 } 192 } 193 194 mViewType[0] = R.layout.menu_card_guide; 195 int index = 1; 196 if (showSetupCard) { 197 channelList.add(dummyChannel); 198 mViewType[index++] = R.layout.menu_card_setup; 199 } 200 if (showDvrCard) { 201 channelList.add(dummyChannel); 202 mViewType[index++] = R.layout.menu_card_dvr; 203 } 204 if (showRecordCard) { 205 channelList.add(currentChannel); 206 mViewType[index++] = R.layout.menu_card_record; 207 } 208 if (showAppLinkCard) { 209 channelList.add(currentChannel); 210 mViewType[index++] = R.layout.menu_card_app_link; 211 } 212 for ( ; index < mViewType.length; ++index) { 213 mViewType[index] = R.layout.menu_card_channel; 214 } 215 channelList.addAll(getRecentChannels()); 216 setItemList(channelList); 217 } 218 getRecentChannels()219 private List<Channel> getRecentChannels() { 220 List<Channel> channelList = new ArrayList<>(); 221 for (Channel channel : mRecommender.recommendChannels(mMaxCount)) { 222 if (channel.isBrowsable()) { 223 channelList.add(channel); 224 } 225 } 226 int count = channelList.size(); 227 // If the number of recommended channels is not enough, add more from the recent channel 228 // list. 229 if (count < mMinCount && mContext instanceof MainActivity) { 230 for (long channelId : ((MainActivity) mContext).getRecentChannels()) { 231 Channel channel = mRecommender.getChannel(channelId); 232 if (channel == null || channelList.contains(channel) 233 || !channel.isBrowsable()) { 234 continue; 235 } 236 channelList.add(channel); 237 if (++count >= mMinCount) { 238 break; 239 } 240 } 241 } 242 return channelList; 243 } 244 } 245