Home | History | Annotate | Download | only in sidepanel
      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;
     18 
     19 import android.media.tv.TvContract.Channels;
     20 import android.os.Bundle;
     21 import android.support.v17.leanback.widget.VerticalGridView;
     22 import android.view.KeyEvent;
     23 import android.view.LayoutInflater;
     24 import android.view.View;
     25 import android.view.ViewGroup;
     26 import android.widget.TextView;
     27 
     28 import com.android.tv.MainActivity;
     29 import com.android.tv.R;
     30 import com.android.tv.data.Channel;
     31 import com.android.tv.data.ChannelNumber;
     32 import com.android.tv.ui.OnRepeatedKeyInterceptListener;
     33 import com.android.tv.util.TvInputManagerHelper;
     34 import com.android.tv.util.Utils;
     35 
     36 import java.util.ArrayList;
     37 import java.util.Collections;
     38 import java.util.Comparator;
     39 import java.util.List;
     40 import java.util.Iterator;
     41 
     42 public class CustomizeChannelListFragment extends SideFragment {
     43     private static final int GROUP_BY_SOURCE = 0;
     44     private static final int GROUP_BY_HD_SD = 1;
     45     private static final String TRACKER_LABEL = "customize channel list";
     46 
     47     private final List<Channel> mChannels = new ArrayList<>();
     48     private final long mInitialChannelId;
     49 
     50     private long mLastFocusedChannelId = Channel.INVALID_ID;
     51 
     52     private int mGroupingType = GROUP_BY_SOURCE;
     53     private TvInputManagerHelper mInputManager;
     54     private Channel.DefaultComparator mChannelComparator;
     55     private boolean mGroupByFragmentRunning;
     56 
     57     private final List<Item> mItems = new ArrayList<>();
     58 
     59     public CustomizeChannelListFragment() {
     60         this(Channel.INVALID_ID);
     61     }
     62 
     63     public CustomizeChannelListFragment(long initialChannelId) {
     64         mInitialChannelId = initialChannelId;
     65     }
     66 
     67     @Override
     68     public void onCreate(Bundle savedInstanceState) {
     69         super.onCreate(savedInstanceState);
     70         mInputManager = getMainActivity().getTvInputManagerHelper();
     71         mChannelComparator = new Channel.DefaultComparator(getActivity(), mInputManager);
     72     }
     73 
     74     @Override
     75     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     76             Bundle savedInstanceState) {
     77         View view = super.onCreateView(inflater, container, savedInstanceState);
     78         VerticalGridView listView = (VerticalGridView) view.findViewById(R.id.side_panel_list);
     79         listView.setOnKeyInterceptListener(new OnRepeatedKeyInterceptListener(listView) {
     80             @Override
     81             public boolean onInterceptKeyEvent(KeyEvent event) {
     82                 // In order to send tune operation once for continuous channel up/down events,
     83                 // we only call the moveToChannel method on ACTION_UP event of channel switch keys.
     84                 if (event.getAction() == KeyEvent.ACTION_UP) {
     85                     switch (event.getKeyCode()) {
     86                         case KeyEvent.KEYCODE_DPAD_UP:
     87                         case KeyEvent.KEYCODE_DPAD_DOWN:
     88                             if (mLastFocusedChannelId != Channel.INVALID_ID) {
     89                                 getMainActivity().tuneToChannel(
     90                                         getChannelDataManager().getChannel(mLastFocusedChannelId));
     91                             }
     92                             break;
     93                     }
     94                 }
     95                 return super.onInterceptKeyEvent(event);
     96             }
     97         });
     98 
     99         if (!mGroupByFragmentRunning) {
    100             getMainActivity().startShrunkenTvView(false, true);
    101 
    102             int initialChannelPosition = INVALID_POSITION;
    103             int i = 0;
    104             for (Item item : mItems) {
    105                 if (item instanceof ChannelItem
    106                         && ((ChannelItem) item).getChannel().getId() == mInitialChannelId) {
    107                     initialChannelPosition = i;
    108                     break;
    109                 }
    110                 ++i;
    111             }
    112             if (initialChannelPosition != INVALID_POSITION) {
    113                 setSelectedPosition(initialChannelPosition);
    114             } else {
    115                 setSelectedPosition(0);
    116             }
    117             mLastFocusedChannelId = mInitialChannelId;
    118             MainActivity tvActivity = getMainActivity();
    119             if (mLastFocusedChannelId != Channel.INVALID_ID &&
    120                     mLastFocusedChannelId != tvActivity.getCurrentChannelId()) {
    121                 tvActivity.tuneToChannel(getChannelDataManager().getChannel(mLastFocusedChannelId));
    122             }
    123         }
    124         mGroupByFragmentRunning = false;
    125         return view;
    126     }
    127 
    128     @Override
    129     public void onDestroyView() {
    130         getChannelDataManager().applyUpdatedValuesToDb();
    131         if (!mGroupByFragmentRunning) {
    132             getMainActivity().endShrunkenTvView();
    133         }
    134         super.onDestroyView();
    135     }
    136 
    137     @Override
    138     protected String getTitle() {
    139         return getString(R.string.side_panel_title_edit_channels_for_an_input);
    140     }
    141 
    142     @Override
    143     public String getTrackerLabel() {
    144         return TRACKER_LABEL;
    145     }
    146 
    147     @Override
    148     protected List<Item> getItemList() {
    149         mItems.clear();
    150         mChannels.clear();
    151         mChannels.addAll(getChannelDataManager().getChannelList());
    152         if (mGroupingType == GROUP_BY_SOURCE) {
    153             addItemForGroupBySource(mItems);
    154         } else {
    155             // GROUP_BY_HD_SD
    156             addItemForGroupByHdSd(mItems);
    157         }
    158         return mItems;
    159     }
    160 
    161     private void cleanUpOneChannelGroupItem(List<Item> items) {
    162         Iterator<Item> iter = items.iterator();
    163         while (iter.hasNext()) {
    164             Item item = iter.next();
    165             if (item instanceof SelectGroupItem) {
    166                 SelectGroupItem selectGroupItem = (SelectGroupItem) item;
    167                 if (selectGroupItem.mChannelItemsInGroup.size() == 1) {
    168                     ((ChannelItem) selectGroupItem.mChannelItemsInGroup.get(0))
    169                             .mSelectGroupItem = null;
    170                     iter.remove();
    171                 }
    172             }
    173         }
    174     }
    175 
    176     private void addItemForGroupBySource(List<Item> items) {
    177         items.add(new GroupBySubMenu(getString(R.string.edit_channels_group_by_sources)));
    178         SelectGroupItem selectGroupItem = null;
    179         ArrayList<Channel> channels = new ArrayList<>(mChannels);
    180         Collections.sort(channels, mChannelComparator);
    181 
    182         String inputId = null;
    183         for (Channel channel: channels) {
    184             if (!channel.getInputId().equals(inputId)) {
    185                 inputId = channel.getInputId();
    186                 String inputLabel = Utils.loadLabel(getActivity(),
    187                         mInputManager.getTvInputInfo(inputId));
    188                 items.add(new DividerItem(inputLabel));
    189                 selectGroupItem = new SelectGroupItem();
    190                 items.add(selectGroupItem);
    191             }
    192             ChannelItem channelItem = new ChannelItem(channel, selectGroupItem);
    193             items.add(channelItem);
    194             selectGroupItem.addChannelItem(channelItem);
    195         }
    196         cleanUpOneChannelGroupItem(items);
    197     }
    198 
    199     private void addItemForGroupByHdSd(List<Item> items) {
    200         items.add(new GroupBySubMenu(getString(R.string.edit_channels_group_by_hd_sd)));
    201         SelectGroupItem selectGroupItem = null;
    202         ArrayList<Channel> channels = new ArrayList<>(mChannels);
    203         Collections.sort(channels, new Comparator<Channel>() {
    204             @Override
    205             public int compare(Channel lhs, Channel rhs) {
    206                 boolean lhsHd = isHdChannel(lhs);
    207                 boolean rhsHd = isHdChannel(rhs);
    208                 if (lhsHd == rhsHd) {
    209                     return ChannelNumber.compare(lhs.getDisplayNumber(), rhs.getDisplayNumber());
    210                 } else {
    211                     return lhsHd ? -1 : 1;
    212                 }
    213             }
    214         });
    215 
    216         Boolean isHdGroup = null;
    217         for (Channel channel: channels) {
    218             boolean isHd = isHdChannel(channel);
    219             if (isHdGroup == null || isHd != isHdGroup) {
    220                 isHdGroup = isHd;
    221                 items.add(new DividerItem(isHd
    222                         ? getString(R.string.edit_channels_group_divider_for_hd)
    223                         : getString(R.string.edit_channels_group_divider_for_sd)));
    224                 selectGroupItem = new SelectGroupItem();
    225                 items.add(selectGroupItem);
    226             }
    227             ChannelItem channelItem = new ChannelItem(channel, selectGroupItem);
    228             items.add(channelItem);
    229             selectGroupItem.addChannelItem(channelItem);
    230         }
    231         cleanUpOneChannelGroupItem(items);
    232     }
    233 
    234     private static boolean isHdChannel(Channel channel) {
    235         String videoFormat = channel.getVideoFormat();
    236         return videoFormat != null &&
    237                 (Channels.VIDEO_FORMAT_720P.equals(videoFormat)
    238                         || Channels.VIDEO_FORMAT_1080I.equals(videoFormat)
    239                         || Channels.VIDEO_FORMAT_1080P.equals(videoFormat)
    240                         || Channels.VIDEO_FORMAT_2160P.equals(videoFormat)
    241                         || Channels.VIDEO_FORMAT_4320P.equals(videoFormat));
    242     }
    243 
    244     private class SelectGroupItem extends ActionItem {
    245         private final List<ChannelItem> mChannelItemsInGroup = new ArrayList<>();
    246         private TextView mTextView;
    247         private boolean mAllChecked;
    248 
    249         public SelectGroupItem() {
    250             super(null);
    251         }
    252 
    253         private void addChannelItem(ChannelItem channelItem) {
    254             mChannelItemsInGroup.add(channelItem);
    255         }
    256 
    257         @Override
    258         protected void onBind(View view) {
    259             super.onBind(view);
    260             mTextView = (TextView) view.findViewById(R.id.title);
    261         }
    262 
    263         @Override
    264         protected void onUpdate() {
    265             super.onUpdate();
    266             mAllChecked = true;
    267             for (ChannelItem channelItem : mChannelItemsInGroup) {
    268                 if (!channelItem.getChannel().isBrowsable()) {
    269                     mAllChecked = false;
    270                     break;
    271                 }
    272             }
    273             mTextView.setText(getString(mAllChecked
    274                     ? R.string.edit_channels_item_deselect_group
    275                     : R.string.edit_channels_item_select_group));
    276         }
    277 
    278         @Override
    279         protected void onSelected() {
    280             for (ChannelItem channelItem : mChannelItemsInGroup) {
    281                 Channel channel = channelItem.getChannel();
    282                 if (channel.isBrowsable() == mAllChecked) {
    283                     getChannelDataManager().updateBrowsable(channel.getId(), !mAllChecked, true);
    284                     channelItem.notifyUpdated();
    285                 }
    286             }
    287             getChannelDataManager().notifyChannelBrowsableChanged();
    288             mAllChecked = !mAllChecked;
    289             mTextView.setText(getString(mAllChecked
    290                     ? R.string.edit_channels_item_deselect_group
    291                     : R.string.edit_channels_item_select_group));
    292         }
    293     }
    294 
    295     private class ChannelItem extends ChannelCheckItem {
    296         private SelectGroupItem mSelectGroupItem;
    297 
    298         public ChannelItem(Channel channel, SelectGroupItem selectGroupItem) {
    299             super(channel, getChannelDataManager(), getProgramDataManager());
    300             mSelectGroupItem = selectGroupItem;
    301         }
    302 
    303         @Override
    304         protected void onUpdate() {
    305             super.onUpdate();
    306             setChecked(getChannel().isBrowsable());
    307         }
    308 
    309         @Override
    310         protected void onSelected() {
    311             super.onSelected();
    312             getChannelDataManager().updateBrowsable(getChannel().getId(), isChecked());
    313             if (mSelectGroupItem != null) {
    314                 mSelectGroupItem.notifyUpdated();
    315             }
    316         }
    317 
    318         @Override
    319         protected void onFocused() {
    320             super.onFocused();
    321             mLastFocusedChannelId = getChannel().getId();
    322         }
    323     }
    324 
    325     private class GroupBySubMenu extends SubMenuItem {
    326         private static final String TRACKER_LABEL = "Group by";
    327         public GroupBySubMenu(String description) {
    328             super(getString(R.string.edit_channels_item_group_by), description,
    329                     getMainActivity().getOverlayManager().getSideFragmentManager());
    330         }
    331 
    332         @Override
    333         protected SideFragment getFragment() {
    334             return new SideFragment() {
    335                 @Override
    336                 protected String getTitle() {
    337                     return getString(R.string.side_panel_title_group_by);
    338                 }
    339                 @Override
    340                 public String getTrackerLabel() {
    341                     return GroupBySubMenu.TRACKER_LABEL;
    342                 }
    343 
    344                 @Override
    345                 protected List<Item> getItemList() {
    346                     List<Item> items = new ArrayList<>();
    347                     items.add(new RadioButtonItem(
    348                             getString(R.string.edit_channels_group_by_sources)) {
    349                         @Override
    350                         protected void onSelected() {
    351                             super.onSelected();
    352                             mGroupingType = GROUP_BY_SOURCE;
    353                             closeFragment();
    354                         }
    355                     });
    356                     items.add(new RadioButtonItem(
    357                             getString(R.string.edit_channels_group_by_hd_sd)) {
    358                         @Override
    359                         protected void onSelected() {
    360                             super.onSelected();
    361                             mGroupingType = GROUP_BY_HD_SD;
    362                             closeFragment();
    363                         }
    364                     });
    365                     ((RadioButtonItem) items.get(mGroupingType)).setChecked(true);
    366                     return items;
    367                 }
    368             };
    369         }
    370 
    371         @Override
    372         protected void onSelected() {
    373             mGroupByFragmentRunning = true;
    374             super.onSelected();
    375         }
    376     }
    377 }
    378