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.ui.sidepanel.parentalcontrols;
18
19import android.database.ContentObserver;
20import android.media.tv.TvContract;
21import android.net.Uri;
22import android.os.Bundle;
23import android.os.Handler;
24import android.support.v17.leanback.widget.VerticalGridView;
25import android.view.KeyEvent;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.TextView;
30
31import com.android.tv.R;
32import com.android.tv.data.Channel;
33import com.android.tv.data.ChannelNumber;
34import com.android.tv.ui.OnRepeatedKeyInterceptListener;
35import com.android.tv.ui.sidepanel.ActionItem;
36import com.android.tv.ui.sidepanel.ChannelCheckItem;
37import com.android.tv.ui.sidepanel.DividerItem;
38import com.android.tv.ui.sidepanel.Item;
39import com.android.tv.ui.sidepanel.SideFragment;
40
41import java.util.ArrayList;
42import java.util.Collections;
43import java.util.Comparator;
44import java.util.List;
45
46public class ChannelsBlockedFragment extends SideFragment {
47    private static final String TRACKER_LABEL = "Channels blocked";
48    private int mBlockedChannelCount;
49    private final List<Channel> mChannels = new ArrayList<>();
50    private long mLastFocusedChannelId = Channel.INVALID_ID;
51    private int mSelectedPosition = INVALID_POSITION;
52    private final ContentObserver mProgramUpdateObserver = new ContentObserver(new Handler()) {
53        @Override
54        public void onChange(boolean selfChange, Uri uri) {
55            notifyItemsChanged();
56        }
57    };
58    private final Item mLockAllItem = new BlockAllItem();
59    private final List<Item> mItems = new ArrayList<>();
60
61    @Override
62    public View onCreateView(LayoutInflater inflater, ViewGroup container,
63            Bundle savedInstanceState) {
64        View view = super.onCreateView(inflater, container, savedInstanceState);
65        if (mSelectedPosition != INVALID_POSITION) {
66            setSelectedPosition(mSelectedPosition);
67        }
68        VerticalGridView listView = (VerticalGridView) view.findViewById(R.id.side_panel_list);
69        listView.setOnKeyInterceptListener(new OnRepeatedKeyInterceptListener(listView) {
70            @Override
71            public boolean onInterceptKeyEvent(KeyEvent event) {
72                // In order to send tune operation once for continuous channel up/down events,
73                // we only call the moveToChannel method on ACTION_UP event of channel switch keys.
74                if (event.getAction() == KeyEvent.ACTION_UP) {
75                    switch (event.getKeyCode()) {
76                        case KeyEvent.KEYCODE_DPAD_UP:
77                        case KeyEvent.KEYCODE_DPAD_DOWN:
78                            if (mLastFocusedChannelId != Channel.INVALID_ID) {
79                                getMainActivity().tuneToChannel(
80                                        getChannelDataManager().getChannel(mLastFocusedChannelId));
81                            }
82                            break;
83                    }
84                }
85                return super.onInterceptKeyEvent(event);
86            }
87        });
88        getActivity().getContentResolver().registerContentObserver(TvContract.Programs.CONTENT_URI,
89                true, mProgramUpdateObserver);
90        getMainActivity().startShrunkenTvView(true, true);
91        return view;
92    }
93
94    @Override
95    public void onDestroyView() {
96        getActivity().getContentResolver().unregisterContentObserver(mProgramUpdateObserver);
97        getChannelDataManager().applyUpdatedValuesToDb();
98        getMainActivity().endShrunkenTvView();
99        super.onDestroyView();
100    }
101
102    @Override
103    protected String getTitle() {
104        return getString(R.string.option_channels_locked);
105    }
106
107    @Override
108    public String getTrackerLabel() {
109        return TRACKER_LABEL;
110    }
111
112    @Override
113    protected List<Item> getItemList() {
114        mItems.clear();
115        mItems.add(mLockAllItem);
116        mChannels.clear();
117        mChannels.addAll(getChannelDataManager().getChannelList());
118        Collections.sort(mChannels, new Comparator<Channel>() {
119            @Override
120            public int compare(Channel lhs, Channel rhs) {
121                if (lhs.isBrowsable() != rhs.isBrowsable()) {
122                    return lhs.isBrowsable() ? -1 : 1;
123                }
124                return ChannelNumber.compare(lhs.getDisplayNumber(), rhs.getDisplayNumber());
125            }
126        });
127
128        final long currentChannelId = getMainActivity().getCurrentChannelId();
129        boolean hasHiddenChannels = false;
130        for (Channel channel : mChannels) {
131            if (!channel.isBrowsable() && !hasHiddenChannels) {
132                mItems.add(new DividerItem(
133                        getString(R.string.option_channels_subheader_hidden)));
134                hasHiddenChannels = true;
135            }
136            mItems.add(new ChannelBlockedItem(channel));
137            if (channel.isLocked()) {
138                ++mBlockedChannelCount;
139            }
140            if (channel.getId() == currentChannelId) {
141                mSelectedPosition = mItems.size() - 1;
142            }
143        }
144        return mItems;
145    }
146
147    private class BlockAllItem extends ActionItem {
148        private TextView mTextView;
149
150        public BlockAllItem() {
151            super(null);
152        }
153
154        @Override
155        protected void onBind(View view) {
156            super.onBind(view);
157            mTextView = (TextView) view.findViewById(R.id.title);
158        }
159
160        @Override
161        protected void onUpdate() {
162            super.onUpdate();
163            updateText();
164        }
165
166        @Override
167        protected void onUnbind() {
168            super.onUnbind();
169            mTextView = null;
170        }
171
172        @Override
173        protected void onSelected() {
174            boolean lock = !areAllChannelsBlocked();
175            for (Channel channel : mChannels) {
176                getChannelDataManager().updateLocked(channel.getId(), lock);
177            }
178            mBlockedChannelCount = lock ? mChannels.size() : 0;
179            notifyItemsChanged();
180        }
181
182        @Override
183        protected void onFocused() {
184            super.onFocused();
185            mLastFocusedChannelId = Channel.INVALID_ID;
186        }
187
188        private void updateText() {
189            mTextView.setText(getString(areAllChannelsBlocked() ?
190                    R.string.option_channels_unlock_all : R.string.option_channels_lock_all));
191        }
192
193        private boolean areAllChannelsBlocked() {
194            return mBlockedChannelCount == mChannels.size();
195        }
196    }
197
198    private class ChannelBlockedItem extends ChannelCheckItem {
199        private ChannelBlockedItem(Channel channel) {
200            super(channel, getChannelDataManager(), getProgramDataManager());
201        }
202
203        @Override
204        protected int getResourceId() {
205            return R.layout.option_item_channel_lock;
206        }
207
208        @Override
209        protected void onUpdate() {
210            super.onUpdate();
211            setChecked(getChannel().isLocked());
212        }
213
214        @Override
215        protected void onSelected() {
216            super.onSelected();
217            getChannelDataManager().updateLocked(getChannel().getId(), isChecked());
218            mBlockedChannelCount += isChecked() ? 1 : -1;
219            notifyItemChanged(mLockAllItem);
220        }
221
222        @Override
223        protected void onFocused() {
224            super.onFocused();
225            mLastFocusedChannelId = getChannel().getId();
226        }
227    }
228}
229