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 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