/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.tv.menu; import android.content.Context; import android.media.tv.TvTrackInfo; import android.support.annotation.VisibleForTesting; import com.android.tv.Features; import com.android.tv.R; import com.android.tv.TvOptionsManager; import com.android.tv.customization.CustomAction; import com.android.tv.data.DisplayMode; import com.android.tv.ui.TvViewUiManager; import com.android.tv.ui.sidepanel.ClosedCaptionFragment; import com.android.tv.ui.sidepanel.DeveloperOptionFragment; import com.android.tv.ui.sidepanel.DisplayModeFragment; import com.android.tv.ui.sidepanel.MultiAudioFragment; import com.android.tv.util.PipInputManager; import java.util.ArrayList; import java.util.List; /* * An adapter of options. */ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter { private static final boolean ENABLE_IN_APP_PIP = false; private int mPositionPipAction; // If mInAppPipAction is false, system-wide PIP is used. private boolean mInAppPipAction = true; public TvOptionsRowAdapter(Context context, List customActions) { super(context, customActions); } @Override protected List createBaseActions() { List actionList = new ArrayList<>(); actionList.add(MenuAction.SELECT_CLOSED_CAPTION_ACTION); setOptionChangedListener(MenuAction.SELECT_CLOSED_CAPTION_ACTION); actionList.add(MenuAction.SELECT_DISPLAY_MODE_ACTION); setOptionChangedListener(MenuAction.SELECT_DISPLAY_MODE_ACTION); actionList.add(MenuAction.PIP_IN_APP_ACTION); setOptionChangedListener(MenuAction.PIP_IN_APP_ACTION); mPositionPipAction = actionList.size() - 1; actionList.add(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION); setOptionChangedListener(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION); actionList.add(MenuAction.MORE_CHANNELS_ACTION); if (DeveloperOptionFragment.shouldShow()) { actionList.add(MenuAction.DEV_ACTION); } actionList.add(MenuAction.SETTINGS_ACTION); if (getCustomActions() != null) { // Adjust Pip action position which will be changed by applying custom actions. for (CustomAction customAction : getCustomActions()) { if (customAction.isFront()) { mPositionPipAction++; } } } return actionList; } @Override protected boolean updateActions() { boolean changed = false; if (updatePipAction()) { changed = true; } if (updateMultiAudioAction()) { changed = true; } if (updateDisplayModeAction()) { changed = true; } return changed; } private boolean updatePipAction() { // There are four states. // Case 1. The device doesn't even have any input for PIP. (e.g. OTT box without HDMI input) // => Remove the icon. // Case 2. The device has one or more inputs for PIP but none of them are currently // available. // => Show the icon but disable it. // Case 3. The device has one or more available PIP inputs and now it's tuned off. // => Show the icon with "Off". // Case 4. The device has one or more available PIP inputs but it's already turned on. // => Show the icon with "On". boolean changed = false; // Case 1 PipInputManager pipInputManager = getMainActivity().getPipInputManager(); if (ENABLE_IN_APP_PIP && pipInputManager.getPipInputSize(false) > 1) { if (!mInAppPipAction) { removeAction(mPositionPipAction); addAction(mPositionPipAction, MenuAction.PIP_IN_APP_ACTION); mInAppPipAction = true; changed = true; } } else { if (mInAppPipAction) { removeAction(mPositionPipAction); mInAppPipAction = false; if (Features.PICTURE_IN_PICTURE.isEnabled(getMainActivity())) { addAction(mPositionPipAction, MenuAction.SYSTEMWIDE_PIP_ACTION); } return true; } return false; } // Case 2 boolean isPipEnabled = getMainActivity().isPipEnabled(); boolean oldEnabled = MenuAction.PIP_IN_APP_ACTION.isEnabled(); boolean newEnabled = pipInputManager.getPipInputSize(true) > 0; if (oldEnabled != newEnabled) { // Should not disable the item if the PIP is already turned on so that the user can // force exit it. if (newEnabled || !isPipEnabled) { MenuAction.PIP_IN_APP_ACTION.setEnabled(newEnabled); changed = true; } } // Case 3 & 4 - we just need to update the icon. MenuAction.PIP_IN_APP_ACTION.setDrawableResId( isPipEnabled ? R.drawable.ic_tvoption_pip : R.drawable.ic_tvoption_pip_off); return changed; } @VisibleForTesting boolean updateMultiAudioAction() { List audioTracks = getMainActivity().getTracks(TvTrackInfo.TYPE_AUDIO); boolean oldEnabled = MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled(); boolean newEnabled = audioTracks != null && audioTracks.size() > 1; if (oldEnabled != newEnabled) { MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.setEnabled(newEnabled); return true; } return false; } private boolean updateDisplayModeAction() { TvViewUiManager uiManager = getMainActivity().getTvViewUiManager(); boolean oldEnabled = MenuAction.SELECT_DISPLAY_MODE_ACTION.isEnabled(); boolean newEnabled = uiManager.isDisplayModeAvailable(DisplayMode.MODE_FULL) || uiManager.isDisplayModeAvailable(DisplayMode.MODE_ZOOM); if (oldEnabled != newEnabled) { MenuAction.SELECT_DISPLAY_MODE_ACTION.setEnabled(newEnabled); return true; } return false; } @Override protected void executeBaseAction(int type) { switch (type) { case TvOptionsManager.OPTION_CLOSED_CAPTIONS: getMainActivity().getOverlayManager().getSideFragmentManager() .show(new ClosedCaptionFragment()); break; case TvOptionsManager.OPTION_DISPLAY_MODE: getMainActivity().getOverlayManager().getSideFragmentManager() .show(new DisplayModeFragment()); break; case TvOptionsManager.OPTION_IN_APP_PIP: getMainActivity().togglePipView(); break; case TvOptionsManager.OPTION_SYSTEMWIDE_PIP: getMainActivity().enterPictureInPictureMode(); break; case TvOptionsManager.OPTION_MULTI_AUDIO: getMainActivity().getOverlayManager().getSideFragmentManager() .show(new MultiAudioFragment()); break; case TvOptionsManager.OPTION_MORE_CHANNELS: getMainActivity().showMerchantCollection(); break; case TvOptionsManager.OPTION_DEVELOPER: getMainActivity().getOverlayManager().getSideFragmentManager() .show(new DeveloperOptionFragment()); break; case TvOptionsManager.OPTION_SETTINGS: getMainActivity().showSettingsFragment(); break; } } }