• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.menu;
18 
19 import android.content.Context;
20 import android.media.tv.TvTrackInfo;
21 import android.support.annotation.VisibleForTesting;
22 import android.support.v4.os.BuildCompat;
23 
24 import com.android.tv.Features;
25 import com.android.tv.R;
26 import com.android.tv.TvOptionsManager;
27 import com.android.tv.customization.CustomAction;
28 import com.android.tv.data.DisplayMode;
29 import com.android.tv.ui.TvViewUiManager;
30 import com.android.tv.ui.sidepanel.ClosedCaptionFragment;
31 import com.android.tv.ui.sidepanel.DisplayModeFragment;
32 import com.android.tv.ui.sidepanel.MultiAudioFragment;
33 import com.android.tv.util.PipInputManager;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /*
39  * An adapter of options.
40  */
41 public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter {
42     private int mPositionPipAction;
43     // If mInAppPipAction is false, system-wide PIP is used.
44     private boolean mInAppPipAction = true;
45     private final Context mContext;
46 
TvOptionsRowAdapter(Context context, List<CustomAction> customActions)47     public TvOptionsRowAdapter(Context context, List<CustomAction> customActions) {
48         super(context, customActions);
49         mContext = context;
50     }
51 
52     @Override
createBaseActions()53     protected List<MenuAction> createBaseActions() {
54         List<MenuAction> actionList = new ArrayList<>();
55         actionList.add(MenuAction.SELECT_CLOSED_CAPTION_ACTION);
56         setOptionChangedListener(MenuAction.SELECT_CLOSED_CAPTION_ACTION);
57         actionList.add(MenuAction.SELECT_DISPLAY_MODE_ACTION);
58         setOptionChangedListener(MenuAction.SELECT_DISPLAY_MODE_ACTION);
59         actionList.add(MenuAction.PIP_IN_APP_ACTION);
60         setOptionChangedListener(MenuAction.PIP_IN_APP_ACTION);
61         mPositionPipAction = actionList.size() - 1;
62         actionList.add(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION);
63         setOptionChangedListener(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION);
64         if (Features.ONBOARDING_PLAY_STORE.isEnabled(getMainActivity())) {
65             actionList.add(MenuAction.MORE_CHANNELS_ACTION);
66         }
67         actionList.add(MenuAction.SETTINGS_ACTION);
68 
69         if (getCustomActions() != null) {
70             // Adjust Pip action position which will be changed by applying custom actions.
71             for (CustomAction customAction : getCustomActions()) {
72                 if (customAction.isFront()) {
73                     mPositionPipAction++;
74                 }
75             }
76         }
77 
78         return actionList;
79     }
80 
81     @Override
updateActions()82     protected boolean updateActions() {
83         boolean changed = false;
84         if (updatePipAction()) {
85             changed = true;
86         }
87         if (updateMultiAudioAction()) {
88             changed = true;
89         }
90         if (updateDisplayModeAction()) {
91             changed = true;
92         }
93         return changed;
94     }
95 
updatePipAction()96     private boolean updatePipAction() {
97         // There are four states.
98         // Case 1. The device doesn't even have any input for PIP. (e.g. OTT box without HDMI input)
99         //    => Remove the icon.
100         // Case 2. The device has one or more inputs for PIP but none of them are currently
101         // available.
102         //    => Show the icon but disable it.
103         // Case 3. The device has one or more available PIP inputs and now it's tuned off.
104         //    => Show the icon with "Off".
105         // Case 4. The device has one or more available PIP inputs but it's already turned on.
106         //    => Show the icon with "On".
107 
108         boolean changed = false;
109 
110         // Case 1
111         PipInputManager pipInputManager = getMainActivity().getPipInputManager();
112         if (pipInputManager.getPipInputSize(false) < 2) {
113             if (mInAppPipAction) {
114                 removeAction(mPositionPipAction);
115                 mInAppPipAction = false;
116                 if (BuildCompat.isAtLeastN()) {
117                     addAction(mPositionPipAction, MenuAction.SYSTEMWIDE_PIP_ACTION);
118                 }
119                 return true;
120             }
121             return false;
122         } else {
123             if (!mInAppPipAction) {
124                 removeAction(mPositionPipAction);
125                 addAction(mPositionPipAction, MenuAction.PIP_IN_APP_ACTION);
126                 mInAppPipAction = true;
127                 changed = true;
128             }
129         }
130 
131         // Case 2
132         boolean isPipEnabled = getMainActivity().isPipEnabled();
133         boolean oldEnabled = MenuAction.PIP_IN_APP_ACTION.isEnabled();
134         boolean newEnabled = pipInputManager.getPipInputSize(true) > 0;
135         if (oldEnabled != newEnabled) {
136             // Should not disable the item if the PIP is already turned on so that the user can
137             // force exit it.
138             if (newEnabled || !isPipEnabled) {
139                 MenuAction.PIP_IN_APP_ACTION.setEnabled(newEnabled);
140                 changed = true;
141             }
142         }
143 
144         // Case 3 & 4 - we just need to update the icon.
145         MenuAction.PIP_IN_APP_ACTION.setDrawableResId(
146                 isPipEnabled ? R.drawable.ic_tvoption_pip : R.drawable.ic_tvoption_pip_off);
147         return changed;
148     }
149 
150     @VisibleForTesting
updateMultiAudioAction()151     boolean updateMultiAudioAction() {
152         List<TvTrackInfo> audioTracks = getMainActivity().getTracks(TvTrackInfo.TYPE_AUDIO);
153         boolean oldEnabled = MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled();
154         boolean newEnabled = audioTracks != null && audioTracks.size() > 1;
155         if (oldEnabled != newEnabled) {
156             MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.setEnabled(newEnabled);
157             return true;
158         }
159         return false;
160     }
161 
updateDisplayModeAction()162     private boolean updateDisplayModeAction() {
163         TvViewUiManager uiManager = getMainActivity().getTvViewUiManager();
164         boolean oldEnabled = MenuAction.SELECT_DISPLAY_MODE_ACTION.isEnabled();
165         boolean newEnabled = uiManager.isDisplayModeAvailable(DisplayMode.MODE_FULL)
166                 || uiManager.isDisplayModeAvailable(DisplayMode.MODE_ZOOM);
167         if (oldEnabled != newEnabled) {
168             MenuAction.SELECT_DISPLAY_MODE_ACTION.setEnabled(newEnabled);
169             return true;
170         }
171         return false;
172     }
173 
174     @Override
executeBaseAction(int type)175     protected void executeBaseAction(int type) {
176         switch (type) {
177             case TvOptionsManager.OPTION_CLOSED_CAPTIONS:
178                 getMainActivity().getOverlayManager().getSideFragmentManager().show(
179                         new ClosedCaptionFragment());
180                 break;
181             case TvOptionsManager.OPTION_DISPLAY_MODE:
182                 getMainActivity().getOverlayManager().getSideFragmentManager().show(
183                         new DisplayModeFragment());
184                 break;
185             case TvOptionsManager.OPTION_IN_APP_PIP:
186                 getMainActivity().togglePipView();
187                 break;
188             case TvOptionsManager.OPTION_SYSTEMWIDE_PIP:
189                 getMainActivity().enterPictureInPictureMode();
190                 break;
191             case TvOptionsManager.OPTION_MULTI_AUDIO:
192                 getMainActivity().getOverlayManager().getSideFragmentManager().show(
193                         new MultiAudioFragment());
194                 break;
195             case TvOptionsManager.OPTION_MORE_CHANNELS:
196                 getMainActivity().showMerchantCollection();
197                 break;
198             case TvOptionsManager.OPTION_SETTINGS:
199                 getMainActivity().showSettingsFragment();
200                 break;
201         }
202     }
203 }
204