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.media.tv.TvInputInfo;
22import android.os.Build;
23import android.support.v4.os.BuildCompat;
24import android.view.View;
25
26import com.android.tv.MainActivity;
27import com.android.tv.R;
28import com.android.tv.TvApplication;
29import com.android.tv.analytics.Tracker;
30import com.android.tv.common.feature.CommonFeatures;
31import com.android.tv.data.Channel;
32import com.android.tv.recommendation.Recommender;
33import com.android.tv.util.SetupUtils;
34import com.android.tv.util.TvInputManagerHelper;
35import com.android.tv.util.Utils;
36
37import java.util.ArrayList;
38import java.util.List;
39
40/**
41 * An adapter of the Channels row.
42 */
43public 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
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
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
138    protected int getLayoutResId(int viewType) {
139        return viewType;
140    }
141
142    @Override
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
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
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