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.ui.sidepanel.parentalcontrols;
18 
19 import android.database.ContentObserver;
20 import android.media.tv.TvContract;
21 import android.net.Uri;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.support.v17.leanback.widget.VerticalGridView;
25 import android.view.KeyEvent;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.TextView;
30 
31 import com.android.tv.R;
32 import com.android.tv.data.Channel;
33 import com.android.tv.data.ChannelNumber;
34 import com.android.tv.ui.OnRepeatedKeyInterceptListener;
35 import com.android.tv.ui.sidepanel.ActionItem;
36 import com.android.tv.ui.sidepanel.ChannelCheckItem;
37 import com.android.tv.ui.sidepanel.DividerItem;
38 import com.android.tv.ui.sidepanel.Item;
39 import com.android.tv.ui.sidepanel.SideFragment;
40 
41 import java.util.ArrayList;
42 import java.util.Collections;
43 import java.util.Comparator;
44 import java.util.List;
45 
46 public 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
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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
onDestroyView()95     public void onDestroyView() {
96         getActivity().getContentResolver().unregisterContentObserver(mProgramUpdateObserver);
97         getChannelDataManager().applyUpdatedValuesToDb();
98         getMainActivity().endShrunkenTvView();
99         super.onDestroyView();
100     }
101 
102     @Override
getTitle()103     protected String getTitle() {
104         return getString(R.string.option_channels_locked);
105     }
106 
107     @Override
getTrackerLabel()108     public String getTrackerLabel() {
109         return TRACKER_LABEL;
110     }
111 
112     @Override
getItemList()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 
BlockAllItem()150         public BlockAllItem() {
151             super(null);
152         }
153 
154         @Override
onBind(View view)155         protected void onBind(View view) {
156             super.onBind(view);
157             mTextView = (TextView) view.findViewById(R.id.title);
158         }
159 
160         @Override
onUpdate()161         protected void onUpdate() {
162             super.onUpdate();
163             updateText();
164         }
165 
166         @Override
onUnbind()167         protected void onUnbind() {
168             super.onUnbind();
169             mTextView = null;
170         }
171 
172         @Override
onSelected()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
onFocused()183         protected void onFocused() {
184             super.onFocused();
185             mLastFocusedChannelId = Channel.INVALID_ID;
186         }
187 
updateText()188         private void updateText() {
189             mTextView.setText(getString(areAllChannelsBlocked() ?
190                     R.string.option_channels_unlock_all : R.string.option_channels_lock_all));
191         }
192 
areAllChannelsBlocked()193         private boolean areAllChannelsBlocked() {
194             return mBlockedChannelCount == mChannels.size();
195         }
196     }
197 
198     private class ChannelBlockedItem extends ChannelCheckItem {
ChannelBlockedItem(Channel channel)199         private ChannelBlockedItem(Channel channel) {
200             super(channel, getChannelDataManager(), getProgramDataManager());
201         }
202 
203         @Override
getResourceId()204         protected int getResourceId() {
205             return R.layout.option_item_channel_lock;
206         }
207 
208         @Override
onUpdate()209         protected void onUpdate() {
210             super.onUpdate();
211             setChecked(getChannel().isLocked());
212         }
213 
214         @Override
onSelected()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
onFocused()223         protected void onFocused() {
224             super.onFocused();
225             mLastFocusedChannelId = getChannel().getId();
226         }
227     }
228 }
229