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