diff options
Diffstat (limited to 'src/com/android/tv/ui/sidepanel')
16 files changed, 418 insertions, 518 deletions
diff --git a/src/com/android/tv/ui/sidepanel/ActionItem.java b/src/com/android/tv/ui/sidepanel/ActionItem.java index 23aff91c..cd70a886 100644 --- a/src/com/android/tv/ui/sidepanel/ActionItem.java +++ b/src/com/android/tv/ui/sidepanel/ActionItem.java @@ -17,7 +17,6 @@ package com.android.tv.ui.sidepanel; import android.view.View; -import android.widget.ImageView; import android.widget.TextView; import com.android.tv.R; @@ -25,24 +24,14 @@ import com.android.tv.R; public abstract class ActionItem extends Item { private final String mTitle; private final String mDescription; - private final int mIconId; public ActionItem(String title) { - this(title, null, 0); + this(title, null); } public ActionItem(String title, String description) { - this(title, description, 0); - } - - public ActionItem(String title, int iconId) { - this(title, null, iconId); - } - - public ActionItem(String title, String description, int iconId) { mTitle = title; mDescription = description; - mIconId = iconId; } @Override @@ -62,12 +51,5 @@ public abstract class ActionItem extends Item { } else { descriptionView.setVisibility(View.GONE); } - ImageView iconView = (ImageView) view.findViewById(R.id.icon); - if (mIconId != 0) { - iconView.setVisibility(View.VISIBLE); - iconView.setImageResource(mIconId); - } else { - iconView.setVisibility(View.GONE); - } } }
\ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/ClosedCaptionFragment.java b/src/com/android/tv/ui/sidepanel/ClosedCaptionFragment.java index d6ccdf6b..341e4350 100644 --- a/src/com/android/tv/ui/sidepanel/ClosedCaptionFragment.java +++ b/src/com/android/tv/ui/sidepanel/ClosedCaptionFragment.java @@ -18,6 +18,7 @@ package com.android.tv.ui.sidepanel; import android.media.tv.TvTrackInfo; import android.os.Bundle; +import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -25,7 +26,6 @@ import android.view.ViewGroup; import com.android.tv.R; import com.android.tv.util.CaptionSettings; -import com.android.tv.util.Utils; import java.util.ArrayList; import java.util.List; @@ -38,8 +38,6 @@ public class ClosedCaptionFragment extends SideFragment { private String mClosedCaptionLanguage; private String mClosedCaptionTrackId; private ClosedCaptionOptionItem mSelectedItem; - private List<Item> mItems; - private boolean mPaused; public ClosedCaptionFragment() { super(KeyEvent.KEYCODE_CAPTIONS, KeyEvent.KEYCODE_S); @@ -63,37 +61,32 @@ public class ClosedCaptionFragment extends SideFragment { mClosedCaptionLanguage = captionSettings.getLanguage(); mClosedCaptionTrackId = captionSettings.getTrackId(); - mItems = new ArrayList<>(); + List<Item> items = new ArrayList<>(); mSelectedItem = null; List<TvTrackInfo> tracks = getMainActivity().getTracks(TvTrackInfo.TYPE_SUBTITLE); if (tracks != null && !tracks.isEmpty()) { - String trackId = captionSettings.isEnabled() ? + String selectedTrackId = captionSettings.isEnabled() ? getMainActivity().getSelectedTrack(TvTrackInfo.TYPE_SUBTITLE) : null; - boolean isEnabled = trackId != null; - - ClosedCaptionOptionItem item = new ClosedCaptionOptionItem( - getString(R.string.closed_caption_option_item_off), - CaptionSettings.OPTION_OFF, null, null); - // Pick 'Off' as default because we may fail to find the matching language. - mSelectedItem = item; - if (!isEnabled) { + ClosedCaptionOptionItem item = new ClosedCaptionOptionItem(null, null); + items.add(item); + if (selectedTrackId == null) { + mSelectedItem = item; item.setChecked(true); + setSelectedPosition(0); } - mItems.add(item); - - for (final TvTrackInfo track : tracks) { - item = new ClosedCaptionOptionItem(getLabel(track), - CaptionSettings.OPTION_ON, track.getId(), track.getLanguage()); - if (isEnabled && track.getId().equals(trackId)) { - item.setChecked(true); + for (int i = 0; i < tracks.size(); i++) { + item = new ClosedCaptionOptionItem(tracks.get(i), i); + if (TextUtils.equals(selectedTrackId, tracks.get(i).getId())) { mSelectedItem = item; + item.setChecked(true); + setSelectedPosition(i + 1); } - mItems.add(item); + items.add(item); } } if (getMainActivity().hasCaptioningSettingsActivity()) { - mItems.add(new ActionItem(getString(R.string.closed_caption_system_settings), + items.add(new ActionItem(getString(R.string.closed_caption_system_settings), getString(R.string.closed_caption_system_settings_description)) { @Override protected void onSelected() { @@ -103,14 +96,14 @@ public class ClosedCaptionFragment extends SideFragment { @Override protected void onFocused() { super.onFocused(); - if (!mPaused && mSelectedItem != null) { + if (mSelectedItem != null) { getMainActivity().selectSubtitleTrack( mSelectedItem.mOption, mSelectedItem.mTrackId); } } }); } - return mItems; + return items; } @Override @@ -120,50 +113,6 @@ public class ClosedCaptionFragment extends SideFragment { } @Override - public void onResume() { - super.onResume(); - if (mPaused) { - // Apply system's closed caption settings to the UI. - CaptionSettings captionSettings = getMainActivity().getCaptionSettings(); - mClosedCaptionOption = CaptionSettings.OPTION_SYSTEM; - mClosedCaptionLanguage = captionSettings.getSystemLanguage(); - ClosedCaptionOptionItem selectedItem = null; - if (captionSettings.isSystemSettingEnabled()) { - for (Item item : mItems) { - if (!(item instanceof ClosedCaptionOptionItem)) { - continue; - } - ClosedCaptionOptionItem captionItem = (ClosedCaptionOptionItem) item; - if (Utils.isEqualLanguage(captionItem.mLanguage, mClosedCaptionLanguage)) { - selectedItem = captionItem; - break; - } - } - } - if (mSelectedItem != null) { - mSelectedItem.setChecked(false); - } - if (selectedItem == null && mItems.get(0) instanceof ClosedCaptionOptionItem) { - selectedItem = (ClosedCaptionOptionItem) mItems.get(0); - } - if (selectedItem != null) { - selectedItem.setChecked(true); - } - // We shouldn't call MainActivity.selectSubtitleTrack() here because - // 1. Tracks are not available because video is just started at this moment. - // 2. MainActivity will apply system settings when video's tracks are available. - mSelectedItem = selectedItem; - } - mPaused = false; - } - - @Override - public void onPause() { - super.onPause(); - mPaused = true; - } - - @Override public void onDestroyView() { if (mResetClosedCaption) { getMainActivity().selectSubtitleLanguage(mClosedCaptionOption, mClosedCaptionLanguage, @@ -172,23 +121,28 @@ public class ClosedCaptionFragment extends SideFragment { super.onDestroyView(); } - private String getLabel(TvTrackInfo track) { - if (track.getLanguage() != null) { + private String getLabel(TvTrackInfo track, Integer trackIndex) { + if (track == null) { + return getString(R.string.closed_caption_option_item_off); + } else if (track.getLanguage() != null) { return new Locale(track.getLanguage()).getDisplayName(); } - return getString(R.string.default_language); + return getString(R.string.closed_caption_unknown_language, trackIndex + 1); } private class ClosedCaptionOptionItem extends RadioButtonItem { private final int mOption; private final String mTrackId; - private final String mLanguage; - private ClosedCaptionOptionItem(String title, int option, String trackId, String language) { - super(title); - mOption = option; - mTrackId = trackId; - mLanguage = language; + private ClosedCaptionOptionItem(TvTrackInfo track, Integer trackIndex) { + super(getLabel(track, trackIndex)); + if (track == null) { + mOption = CaptionSettings.OPTION_OFF; + mTrackId = null; + } else { + mOption = CaptionSettings.OPTION_ON; + mTrackId = track.getId(); + } } @Override diff --git a/src/com/android/tv/ui/sidepanel/CompoundButtonItem.java b/src/com/android/tv/ui/sidepanel/CompoundButtonItem.java index 7613a9a2..c2746937 100644 --- a/src/com/android/tv/ui/sidepanel/CompoundButtonItem.java +++ b/src/com/android/tv/ui/sidepanel/CompoundButtonItem.java @@ -23,9 +23,12 @@ import android.widget.TextView; import com.android.tv.R; public abstract class CompoundButtonItem extends Item { + private static int sDefaultMaxLine = 0; + private final String mCheckedTitle; private final String mUncheckedTitle; private final String mDescription; + private final int mMaxLine; private boolean mChecked; private TextView mTextView; private CompoundButton mCompoundButton; @@ -38,6 +41,15 @@ public abstract class CompoundButtonItem extends Item { mCheckedTitle = checkedTitle; mUncheckedTitle = uncheckedTitle; mDescription = description; + mMaxLine = 0; + } + + public CompoundButtonItem(String checkedTitle, String uncheckedTitle, String description, + int maxLine) { + mCheckedTitle = checkedTitle; + mUncheckedTitle = uncheckedTitle; + mDescription = description; + mMaxLine = maxLine; } protected abstract int getCompoundButtonId(); @@ -57,6 +69,15 @@ public abstract class CompoundButtonItem extends Item { mTextView = (TextView) view.findViewById(getTitleViewId()); TextView descriptionView = (TextView) view.findViewById(getDescriptionViewId()); if (mDescription != null) { + if (mMaxLine != 0) { + descriptionView.setMaxLines(mMaxLine); + } else { + if (sDefaultMaxLine == 0) { + sDefaultMaxLine = view.getContext().getResources() + .getInteger(R.integer.option_item_description_max_lines); + } + descriptionView.setMaxLines(sDefaultMaxLine); + } descriptionView.setVisibility(View.VISIBLE); descriptionView.setText(mDescription); } else { diff --git a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java index 9cc54ed2..297e69d9 100644 --- a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java +++ b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java @@ -16,6 +16,8 @@ package com.android.tv.ui.sidepanel; +import android.content.Context; +import android.content.SharedPreferences; import android.media.tv.TvContract.Channels; import android.os.Bundle; import android.support.v17.leanback.widget.VerticalGridView; @@ -27,6 +29,7 @@ import android.widget.TextView; import com.android.tv.MainActivity; import com.android.tv.R; +import com.android.tv.common.SharedPreferencesUtils; import com.android.tv.data.Channel; import com.android.tv.data.ChannelNumber; import com.android.tv.ui.OnRepeatedKeyInterceptListener; @@ -36,39 +39,38 @@ import com.android.tv.util.Utils; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.List; import java.util.Iterator; +import java.util.List; public class CustomizeChannelListFragment extends SideFragment { private static final int GROUP_BY_SOURCE = 0; private static final int GROUP_BY_HD_SD = 1; private static final String TRACKER_LABEL = "customize channel list"; - private final List<Channel> mChannels = new ArrayList<>(); - private final long mInitialChannelId; + private static final String PREF_KEY_GROUP_SETTINGS = "pref_key_group_settigns"; + private final List<Channel> mChannels = new ArrayList<>(); + private long mInitialChannelId = Channel.INVALID_ID; private long mLastFocusedChannelId = Channel.INVALID_ID; - private int mGroupingType = GROUP_BY_SOURCE; + private static Integer sGroupingType; private TvInputManagerHelper mInputManager; private Channel.DefaultComparator mChannelComparator; private boolean mGroupByFragmentRunning; private final List<Item> mItems = new ArrayList<>(); - public CustomizeChannelListFragment() { - this(Channel.INVALID_ID); - } - - public CustomizeChannelListFragment(long initialChannelId) { - mInitialChannelId = initialChannelId; - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mInputManager = getMainActivity().getTvInputManagerHelper(); + mInitialChannelId = getMainActivity().getCurrentChannelId(); mChannelComparator = new Channel.DefaultComparator(getActivity(), mInputManager); + if (sGroupingType == null) { + SharedPreferences sharedPreferences = getContext().getSharedPreferences( + SharedPreferencesUtils.SHARED_PREF_UI_SETTINGS, Context.MODE_PRIVATE); + sGroupingType = sharedPreferences.getInt(PREF_KEY_GROUP_SETTINGS, GROUP_BY_SOURCE); + } } @Override @@ -128,13 +130,16 @@ public class CustomizeChannelListFragment extends SideFragment { @Override public void onDestroyView() { getChannelDataManager().applyUpdatedValuesToDb(); - if (!mGroupByFragmentRunning) { - getMainActivity().endShrunkenTvView(); - } super.onDestroyView(); } @Override + public void onDestroy() { + super.onDestroy(); + getMainActivity().endShrunkenTvView(); + } + + @Override protected String getTitle() { return getString(R.string.side_panel_title_edit_channels_for_an_input); } @@ -149,7 +154,7 @@ public class CustomizeChannelListFragment extends SideFragment { mItems.clear(); mChannels.clear(); mChannels.addAll(getChannelDataManager().getChannelList()); - if (mGroupingType == GROUP_BY_SOURCE) { + if (sGroupingType == GROUP_BY_SOURCE) { addItemForGroupBySource(mItems); } else { // GROUP_BY_HD_SD @@ -321,6 +326,49 @@ public class CustomizeChannelListFragment extends SideFragment { } } + public static class GroupByFragment extends SideFragment { + @Override + protected String getTitle() { + return getString(R.string.side_panel_title_group_by); + } + @Override + public String getTrackerLabel() { + return GroupBySubMenu.TRACKER_LABEL; + } + + @Override + protected List<Item> getItemList() { + List<Item> items = new ArrayList<>(); + items.add(new RadioButtonItem( + getString(R.string.edit_channels_group_by_sources)) { + @Override + protected void onSelected() { + super.onSelected(); + setGroupingType(GROUP_BY_SOURCE); + closeFragment(); + } + }); + items.add(new RadioButtonItem( + getString(R.string.edit_channels_group_by_hd_sd)) { + @Override + protected void onSelected() { + super.onSelected(); + setGroupingType(GROUP_BY_HD_SD); + closeFragment(); + } + }); + ((RadioButtonItem) items.get(sGroupingType)).setChecked(true); + return items; + } + + private void setGroupingType(int groupingType) { + sGroupingType = groupingType; + SharedPreferences sharedPreferences = getContext().getSharedPreferences( + SharedPreferencesUtils.SHARED_PREF_UI_SETTINGS, Context.MODE_PRIVATE); + sharedPreferences.edit().putInt(PREF_KEY_GROUP_SETTINGS, groupingType).apply(); + } + } + private class GroupBySubMenu extends SubMenuItem { private static final String TRACKER_LABEL = "Group by"; public GroupBySubMenu(String description) { @@ -330,41 +378,7 @@ public class CustomizeChannelListFragment extends SideFragment { @Override protected SideFragment getFragment() { - return new SideFragment() { - @Override - protected String getTitle() { - return getString(R.string.side_panel_title_group_by); - } - @Override - public String getTrackerLabel() { - return GroupBySubMenu.TRACKER_LABEL; - } - - @Override - protected List<Item> getItemList() { - List<Item> items = new ArrayList<>(); - items.add(new RadioButtonItem( - getString(R.string.edit_channels_group_by_sources)) { - @Override - protected void onSelected() { - super.onSelected(); - mGroupingType = GROUP_BY_SOURCE; - closeFragment(); - } - }); - items.add(new RadioButtonItem( - getString(R.string.edit_channels_group_by_hd_sd)) { - @Override - protected void onSelected() { - super.onSelected(); - mGroupingType = GROUP_BY_HD_SD; - closeFragment(); - } - }); - ((RadioButtonItem) items.get(mGroupingType)).setChecked(true); - return items; - } - }; + return new GroupByFragment(); } @Override diff --git a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java index 0d189cca..f633fa5a 100644 --- a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java +++ b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java @@ -18,8 +18,6 @@ package com.android.tv.ui.sidepanel; import android.accounts.Account; import android.app.Activity; -import android.app.ApplicationErrorReport; -import android.content.Intent; import android.support.annotation.NonNull; import android.util.Log; import android.widget.Toast; @@ -27,9 +25,11 @@ import android.widget.Toast; import com.android.tv.R; import com.android.tv.TvApplication; import com.android.tv.common.BuildConfig; +import com.android.tv.common.feature.CommonFeatures; import com.android.tv.data.epg.EpgFetcher; import com.android.tv.experiments.Experiments; import com.android.tv.tuner.TunerPreferences; +import com.android.tv.util.Utils; import java.util.ArrayList; import java.util.List; @@ -54,7 +54,15 @@ public class DeveloperOptionFragment extends SideFragment { @Override protected List<Item> getItemList() { List<Item> items = new ArrayList<>(); - if (BuildConfig.ENG) { + if (CommonFeatures.DVR.isEnabled(getContext())) { + items.add(new ActionItem(getString(R.string.dev_item_dvr_history)) { + @Override + protected void onSelected() { + getMainActivity().getOverlayManager().showDvrHistoryDialog(); + } + }); + } + if (Utils.isDeveloper()) { items.add(new ActionItem(getString(R.string.dev_item_watch_history)) { @Override protected void onSelected() { @@ -62,18 +70,6 @@ public class DeveloperOptionFragment extends SideFragment { } }); } - items.add(new ActionItem(getString(R.string.dev_item_send_feedback)) { - @Override - protected void onSelected() { - Intent intent = new Intent(Intent.ACTION_APP_ERROR); - ApplicationErrorReport report = new ApplicationErrorReport(); - report.packageName = report.processName = getContext().getPackageName(); - report.time = System.currentTimeMillis(); - report.type = ApplicationErrorReport.TYPE_NONE; - intent.putExtra(Intent.EXTRA_BUG_REPORT, report); - startActivityForResult(intent, 0); - } - }); items.add(new SwitchItem(getString(R.string.dev_item_store_ts_on), getString(R.string.dev_item_store_ts_off), getString(R.string.dev_item_store_ts_description)) { @@ -89,13 +85,18 @@ public class DeveloperOptionFragment extends SideFragment { TunerPreferences.setStoreTsStream(getContext(), isChecked()); } }); + if (Utils.isDeveloper()) { + items.add( + new ActionItem(getString(R.string.dev_item_show_performance_monitor_log)) { + @Override + protected void onSelected() { + TvApplication.getSingletons(getContext()) + .getPerformanceMonitor() + .startPerformanceMonitorEventDebugActivity(getContext()); + } + }); + } return items; } - - /** True if there is the dev options menu */ - public static boolean shouldShow() { - return Experiments.ENABLE_DEVELOPER_FEATURES.get() || BuildConfig.ENG; - } - -} +}
\ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/Item.java b/src/com/android/tv/ui/sidepanel/Item.java index 00f16427..4e47e75b 100644 --- a/src/com/android/tv/ui/sidepanel/Item.java +++ b/src/com/android/tv/ui/sidepanel/Item.java @@ -24,6 +24,7 @@ import android.view.ViewGroup; public abstract class Item { private View mItemView; private boolean mEnabled = true; + private boolean mClickable = true; public void setEnabled(boolean enabled) { if (mEnabled != enabled) { @@ -35,6 +36,16 @@ public abstract class Item { } /** + * Sets the item to be clickable or not. + */ + public void setClickable(boolean clickable) { + mClickable = clickable; + if (mItemView != null) { + mItemView.setClickable(clickable); + } + } + + /** * Returns whether this item is enabled. */ public boolean isEnabled() { @@ -64,6 +75,7 @@ public abstract class Item { */ protected void onUpdate() { setEnabledInternal(mItemView, mEnabled); + mItemView.setClickable(mClickable); } protected abstract void onSelected(); diff --git a/src/com/android/tv/ui/sidepanel/PipInputSelectorFragment.java b/src/com/android/tv/ui/sidepanel/PipInputSelectorFragment.java deleted file mode 100644 index dec017a8..00000000 --- a/src/com/android/tv/ui/sidepanel/PipInputSelectorFragment.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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.ui.sidepanel; - -import android.media.tv.TvInputInfo; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.android.tv.R; -import com.android.tv.util.PipInputManager; -import com.android.tv.util.PipInputManager.PipInput; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class PipInputSelectorFragment extends SideFragment { - private static final String TAG = "PipInputSelector"; - private static final String TRACKER_LABEL = "PIP input source"; - - private final List<Item> mInputItems = new ArrayList<>(); - private PipInputManager mPipInputManager; - private PipInput mInitialPipInput; - private boolean mSelected; - - private final PipInputManager.Listener mPipInputListener = new PipInputManager.Listener() { - @Override - public void onPipInputStateUpdated() { - notifyDataSetChanged(); - } - - @Override - public void onPipInputListUpdated() { - refreshInputList(); - setItems(mInputItems); - } - }; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mPipInputManager = getMainActivity().getPipInputManager(); - mPipInputManager.addListener(mPipInputListener); - getMainActivity().startShrunkenTvView(false, false); - return super.onCreateView(inflater, container, savedInstanceState); - } - - @Override - public void onStart() { - super.onStart(); - mInitialPipInput = mPipInputManager.getPipInput(getMainActivity().getPipChannel()); - if (mInitialPipInput == null) { - Log.w(TAG, "PIP should be on"); - closeFragment(); - } - int count = 0; - for (Item item : mInputItems) { - InputItem inputItem = (InputItem) item; - if (Objects.equals(inputItem.mPipInput, mInitialPipInput)) { - setSelectedPosition(count); - break; - } - ++count; - } - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - mPipInputManager.removeListener(mPipInputListener); - if (!mSelected) { - getMainActivity().tuneToChannelForPip(mInitialPipInput.getChannel()); - } - getMainActivity().endShrunkenTvView(); - } - - @Override - protected String getTitle() { - return getString(R.string.side_panel_title_pip_input_source); - } - - @Override - public String getTrackerLabel() { - return TRACKER_LABEL; - } - - @Override - protected List<Item> getItemList() { - refreshInputList(); - return mInputItems; - } - - private void refreshInputList() { - mInputItems.clear(); - for (PipInput input : mPipInputManager.getPipInputList(false)) { - mInputItems.add(new InputItem(input)); - } - } - - private class InputItem extends RadioButtonItem { - private final PipInput mPipInput; - - private InputItem(PipInput input) { - super(input.getLongLabel()); - mPipInput = input; - setEnabled(isAvailable()); - } - - @Override - protected void onUpdate() { - super.onUpdate(); - setEnabled(mPipInput.isAvailable()); - setChecked(mPipInput == mInitialPipInput); - } - - @Override - protected void onFocused() { - super.onFocused(); - if (isEnabled()) { - getMainActivity().tuneToChannelForPip(mPipInput.getChannel()); - } - } - - @Override - protected void onSelected() { - super.onSelected(); - if (isEnabled()) { - mSelected = true; - closeFragment(); - } - } - - private boolean isAvailable() { - if (!mPipInput.isAvailable()) { - return false; - } - - // If this input shares the same parent with the current main input, you cannot select - // it. (E.g. two HDMI CEC devices that are connected to HDMI port 1 through an A/V - // receiver.) - PipInput pipInput = mPipInputManager.getPipInput(getMainActivity().getCurrentChannel()); - if (pipInput == null) { - return false; - } - TvInputInfo mainInputInfo = pipInput.getInputInfo(); - TvInputInfo pipInputInfo = mPipInput.getInputInfo(); - return mainInputInfo == null || pipInputInfo == null - || !TextUtils.equals(mainInputInfo.getId(), pipInputInfo.getId()) - && !TextUtils.equals(mainInputInfo.getParentId(), pipInputInfo.getParentId()); - } - } -} diff --git a/src/com/android/tv/ui/sidepanel/SettingsFragment.java b/src/com/android/tv/ui/sidepanel/SettingsFragment.java index e8033a22..6a5b510c 100644 --- a/src/com/android/tv/ui/sidepanel/SettingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/SettingsFragment.java @@ -16,18 +16,25 @@ package com.android.tv.ui.sidepanel; +import static com.android.tv.Features.TUNER; + +import android.app.ApplicationErrorReport; +import android.content.Intent; +import android.media.tv.TvInputInfo; import android.view.View; import android.widget.Toast; import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvApplication; +import com.android.tv.customization.TvCustomizationManager; import com.android.tv.dialog.PinDialogFragment; -import com.android.tv.dialog.WebDialogFragment; -import com.android.tv.license.LicenseUtils; -import com.android.tv.ui.sidepanel.parentalcontrols.ParentalControlsFragment; +import com.android.tv.license.LicenseSideFragment; +import com.android.tv.license.Licenses; +import com.android.tv.tuner.TunerPreferences; import com.android.tv.util.PermissionUtils; import com.android.tv.util.SetupUtils; +import com.android.tv.util.Utils; import java.util.ArrayList; import java.util.List; @@ -38,33 +45,6 @@ import java.util.List; public class SettingsFragment extends SideFragment { private static final String TRACKER_LABEL = "settings"; - private final long mCurrentChannelId; - - public SettingsFragment(long currentChannelId) { - mCurrentChannelId = currentChannelId; - } - - /** - * Opens a dialog showing open source licenses. - */ - public static final class LicenseActionItem extends ActionItem { - public final static String DIALOG_TAG = LicenseActionItem.class.getSimpleName(); - public static final String TRACKER_LABEL = "Open Source Licenses"; - private final MainActivity mMainActivity; - - public LicenseActionItem(MainActivity mainActivity) { - super(mainActivity.getString(R.string.settings_menu_licenses)); - mMainActivity = mainActivity; - } - - @Override - protected void onSelected() { - WebDialogFragment dialog = WebDialogFragment.newInstance(LicenseUtils.LICENSE_FILE, - mMainActivity.getString(R.string.dialog_title_licenses), TRACKER_LABEL); - mMainActivity.getOverlayManager().showDialogFragment(DIALOG_TAG, dialog, false); - } - } - @Override protected String getTitle() { return getResources().getString(R.string.side_panel_title_settings); @@ -80,11 +60,11 @@ public class SettingsFragment extends SideFragment { List<Item> items = new ArrayList<>(); final Item customizeChannelListItem = new SubMenuItem( getString(R.string.settings_channel_source_item_customize_channels), - getString(R.string.settings_channel_source_item_customize_channels_description), 0, + getString(R.string.settings_channel_source_item_customize_channels_description), getMainActivity().getOverlayManager().getSideFragmentManager()) { @Override protected SideFragment getFragment() { - return new CustomizeChannelListFragment(mCurrentChannelId); + return new CustomizeChannelListFragment(); } @Override @@ -122,25 +102,11 @@ public class SettingsFragment extends SideFragment { : R.string.option_toggle_parental_controls_off)) { @Override protected void onSelected() { - final MainActivity tvActivity = getMainActivity(); - final SideFragmentManager sideFragmentManager = tvActivity.getOverlayManager() - .getSideFragmentManager(); - sideFragmentManager.hideSidePanel(true); - PinDialogFragment fragment = new PinDialogFragment( - PinDialogFragment.PIN_DIALOG_TYPE_ENTER_PIN, - new PinDialogFragment.ResultListener() { - @Override - public void done(boolean success) { - if (success) { - sideFragmentManager - .show(new ParentalControlsFragment(), false); - sideFragmentManager.showSidePanel(true); - } else { - sideFragmentManager.hideAll(false); - } - } - }); - tvActivity.getOverlayManager() + getMainActivity().getOverlayManager() + .getSideFragmentManager().hideSidePanel(true); + PinDialogFragment fragment = PinDialogFragment + .create(PinDialogFragment.PIN_DIALOG_TYPE_ENTER_PIN); + getMainActivity().getOverlayManager() .showDialogFragment(PinDialogFragment.DIALOG_TAG, fragment, true); } }); @@ -149,12 +115,73 @@ public class SettingsFragment extends SideFragment { // But, we may be able to turn on channel lock feature regardless of the permission. // It's TBD. } - if (LicenseUtils.hasLicenses(activity.getAssets())) { - items.add(new LicenseActionItem(activity)); + boolean showTrickplaySetting = false; + if (TUNER.isEnabled(getContext())) { + for (TvInputInfo inputInfo : TvApplication.getSingletons(getContext()) + .getTvInputManagerHelper().getTvInputInfos(true, true)) { + if (Utils.isInternalTvInput(getContext(), inputInfo.getId())) { + showTrickplaySetting = true; + break; + } + } + if (showTrickplaySetting) { + showTrickplaySetting = + TvCustomizationManager.getTrickplayMode(getContext()) + == TvCustomizationManager.TRICKPLAY_MODE_ENABLED; + } + } + if (showTrickplaySetting) { + items.add( + new SwitchItem(getString(R.string.settings_trickplay), + getString(R.string.settings_trickplay), + getString(R.string.settings_trickplay_description), + getResources().getInteger(R.integer.trickplay_description_max_lines)) { + @Override + protected void onUpdate() { + super.onUpdate(); + boolean enabled = TunerPreferences.getTrickplaySetting(getContext()) + != TunerPreferences.TRICKPLAY_SETTING_DISABLED; + setChecked(enabled); + } + + @Override + protected void onSelected() { + super.onSelected(); + @TunerPreferences.TrickplaySetting int setting = + isChecked() ? TunerPreferences.TRICKPLAY_SETTING_ENABLED + : TunerPreferences.TRICKPLAY_SETTING_DISABLED; + TunerPreferences.setTrickplaySetting(getContext(), setting); + } + }); + } + items.add(new ActionItem(getString(R.string.settings_send_feedback)) { + @Override + protected void onSelected() { + Intent intent = new Intent(Intent.ACTION_APP_ERROR); + ApplicationErrorReport report = new ApplicationErrorReport(); + report.packageName = report.processName = getContext().getPackageName(); + report.time = System.currentTimeMillis(); + report.type = ApplicationErrorReport.TYPE_NONE; + intent.putExtra(Intent.EXTRA_BUG_REPORT, report); + startActivityForResult(intent, 0); + } + }); + if (Licenses.hasLicenses(getContext())) { + items.add( + new SubMenuItem( + getString(R.string.settings_menu_licenses), + getMainActivity().getOverlayManager().getSideFragmentManager()) { + @Override + protected SideFragment getFragment() { + return new LicenseSideFragment(); + } + }); } // Show version. - items.add(new SimpleItem(getString(R.string.settings_menu_version), - ((TvApplication) activity.getApplicationContext()).getVersionName())); + SimpleActionItem version = new SimpleActionItem(getString(R.string.settings_menu_version), + ((TvApplication) activity.getApplicationContext()).getVersionName()); + version.setClickable(false); + items.add(version); return items; } diff --git a/src/com/android/tv/ui/sidepanel/SideFragment.java b/src/com/android/tv/ui/sidepanel/SideFragment.java index 8df56cd2..6bd921a2 100644 --- a/src/com/android/tv/ui/sidepanel/SideFragment.java +++ b/src/com/android/tv/ui/sidepanel/SideFragment.java @@ -26,32 +26,36 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.TextView; import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvApplication; -import com.android.tv.analytics.DurationTimer; +import com.android.tv.util.DurationTimer; import com.android.tv.analytics.HasTrackerLabel; import com.android.tv.analytics.Tracker; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ProgramDataManager; import com.android.tv.util.SystemProperties; +import com.android.tv.util.ViewCache; import java.util.List; -public abstract class SideFragment extends Fragment implements HasTrackerLabel { +public abstract class SideFragment<T extends Item> extends Fragment implements HasTrackerLabel { public static final int INVALID_POSITION = -1; - private static final int RECYCLED_VIEW_POOL_SIZE = 7; - private static final int[] PRELOADED_VIEW_IDS = { + private static final int PRELOAD_VIEW_SIZE = 7; + private static final int[] PRELOAD_VIEW_IDS = { R.layout.option_item_radio_button, R.layout.option_item_channel_lock, R.layout.option_item_check_box, - R.layout.option_item_channel_check + R.layout.option_item_channel_check, + R.layout.option_item_action }; - private static RecyclerView.RecycledViewPool sRecycledViewPool; + private static RecyclerView.RecycledViewPool sRecycledViewPool = + new RecyclerView.RecycledViewPool(); private VerticalGridView mListView; private ItemAdapter mAdapter; @@ -89,14 +93,8 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - if (sRecycledViewPool == null) { - // sRecycledViewPool should be initialized by calling preloadRecycledViews() - // before the entering animation of this fragment starts, - // because it takes long time and if it is called after the animation starts (e.g. here) - // it can affect the animation. - throw new IllegalStateException("The RecyclerView pool has not been initialized."); - } - View view = inflater.inflate(getFragmentLayoutResourceId(), container, false); + View view = ViewCache.getInstance().getOrCreateView( + inflater, getFragmentLayoutResourceId(), container); TextView textView = (TextView) view.findViewById(R.id.side_panel_title); textView.setText(getTitle()); @@ -158,7 +156,7 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel { return mListView.getSelectedPosition(); } - public void setItems(List<Item> items) { + public void setItems(List<T> items) { mAdapter.reset(items); } @@ -229,56 +227,50 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel { protected abstract String getTitle(); @Override public abstract String getTrackerLabel(); - protected abstract List<Item> getItemList(); + protected abstract List<T> getItemList(); public interface SideFragmentListener { void onSideFragmentViewDestroyed(); } /** - * Preloads the view holders. + * Preloads the item views. */ - public static void preloadRecycledViews(Context context) { - if (sRecycledViewPool != null) { - return; - } - sRecycledViewPool = new RecyclerView.RecycledViewPool(); - LayoutInflater inflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - for (int id : PRELOADED_VIEW_IDS) { - sRecycledViewPool.setMaxRecycledViews(id, RECYCLED_VIEW_POOL_SIZE); - for (int j = 0; j < RECYCLED_VIEW_POOL_SIZE; ++j) { - ItemAdapter.ViewHolder viewHolder = new ItemAdapter.ViewHolder( - inflater.inflate(id, null, false)); - sRecycledViewPool.putRecycledView(viewHolder); - } + public static void preloadItemViews(Context context) { + ViewCache.getInstance().putView( + context, R.layout.option_fragment, new FrameLayout(context), 1); + VerticalGridView fakeParent = new VerticalGridView(context); + for (int id : PRELOAD_VIEW_IDS) { + sRecycledViewPool.setMaxRecycledViews(id, PRELOAD_VIEW_SIZE); + ViewCache.getInstance().putView(context, id, fakeParent, PRELOAD_VIEW_SIZE); } } /** - * Releases the pre-loaded view holders. + * Releases the recycled view pool. */ - public static void releasePreloadedRecycledViews() { - sRecycledViewPool = null; + public static void releaseRecycledViewPool() { + sRecycledViewPool.clear(); } - private static class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> { + private static class ItemAdapter<T extends Item> extends RecyclerView.Adapter<ViewHolder> { private final LayoutInflater mLayoutInflater; - private List<Item> mItems; + private List<T> mItems; - private ItemAdapter(LayoutInflater layoutInflater, List<Item> items) { + private ItemAdapter(LayoutInflater layoutInflater, List<T> items) { mLayoutInflater = layoutInflater; mItems = items; } - private void reset(List<Item> items) { + private void reset(List<T> items) { mItems = items; notifyDataSetChanged(); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new ViewHolder(mLayoutInflater.inflate(viewType, parent, false)); + View view = ViewCache.getInstance().getOrCreateView(mLayoutInflater, viewType, parent); + return new ViewHolder(view); } @Override @@ -301,11 +293,11 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel { return mItems == null ? 0 : mItems.size(); } - private Item getItem(int position) { + private T getItem(int position) { return mItems.get(position); } - private void clearRadioGroup(Item item) { + private void clearRadioGroup(T item) { int position = mItems.indexOf(item); for (int i = position - 1; i >= 0; --i) { if ((item = mItems.get(i)) instanceof RadioButtonItem) { @@ -322,55 +314,57 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel { } } } + } - private static class ViewHolder extends RecyclerView.ViewHolder - implements View.OnClickListener, View.OnFocusChangeListener { - private ItemAdapter mAdapter; - public Item mItem; + private static class ViewHolder extends RecyclerView.ViewHolder + implements View.OnClickListener, View.OnFocusChangeListener { + private ItemAdapter mAdapter; + public Item mItem; - private ViewHolder(View view) { - super(view); - itemView.setOnClickListener(this); - itemView.setOnFocusChangeListener(this); - } + private ViewHolder(View view) { + super(view); + itemView.setOnClickListener(this); + itemView.setOnFocusChangeListener(this); + } - public void onBind(ItemAdapter adapter, Item item) { - mAdapter = adapter; - mItem = item; - mItem.onBind(itemView); - mItem.onUpdate(); - } + public void onBind(ItemAdapter adapter, Item item) { + mAdapter = adapter; + mItem = item; + mItem.onBind(itemView); + mItem.onUpdate(); + } - public void onUnbind() { - mItem.onUnbind(); - mItem = null; - mAdapter = null; - } + public void onUnbind() { + mItem.onUnbind(); + mItem = null; + mAdapter = null; + } - @Override - public void onClick(View view) { - if (mItem instanceof RadioButtonItem) { - mAdapter.clearRadioGroup(mItem); - } - if (view.getBackground() instanceof RippleDrawable) { - view.postDelayed(new Runnable() { - @Override - public void run() { - if (mItem != null) { - mItem.onSelected(); + @Override + public void onClick(View view) { + if (mItem instanceof RadioButtonItem) { + mAdapter.clearRadioGroup(mItem); + } + if (view.getBackground() instanceof RippleDrawable) { + view.postDelayed( + new Runnable() { + @Override + public void run() { + if (mItem != null) { + mItem.onSelected(); + } } - } - }, view.getResources().getInteger(R.integer.side_panel_ripple_anim_duration)); - } else { - mItem.onSelected(); - } + }, + view.getResources().getInteger(R.integer.side_panel_ripple_anim_duration)); + } else { + mItem.onSelected(); } + } - @Override - public void onFocusChange(View view, boolean focusGained) { - if (focusGained) { - mItem.onFocused(); - } + @Override + public void onFocusChange(View view, boolean focusGained) { + if (focusGained) { + mItem.onFocused(); } } } diff --git a/src/com/android/tv/ui/sidepanel/SideFragmentManager.java b/src/com/android/tv/ui/sidepanel/SideFragmentManager.java index 553cd9d7..d02d3fb7 100644 --- a/src/com/android/tv/ui/sidepanel/SideFragmentManager.java +++ b/src/com/android/tv/ui/sidepanel/SideFragmentManager.java @@ -24,6 +24,7 @@ import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Handler; import android.view.View; +import android.view.ViewTreeObserver; import com.android.tv.R; @@ -34,6 +35,7 @@ public class SideFragmentManager { private final FragmentManager mFragmentManager; private final Runnable mPreShowRunnable; private final Runnable mPostHideRunnable; + private ViewTreeObserver.OnGlobalLayoutListener mShowOnGlobalLayoutListener; // To get the count reliably while using popBackStack(), // instead of using getBackStackEntryCount() with popBackStackImmediate(). @@ -99,17 +101,10 @@ public class SideFragmentManager { * Shows the given {@link SideFragment}. */ public void show(SideFragment sideFragment, boolean showEnterAnimation) { - SideFragment.preloadRecycledViews(mActivity); if (isHiding()) { mHideAnimator.end(); } boolean isFirst = (mFragmentCount == 0); - if (isFirst) { - if (mPreShowRunnable != null) { - mPreShowRunnable.run(); - } - } - FragmentTransaction ft = mFragmentManager.beginTransaction(); if (!isFirst) { ft.setCustomAnimations( @@ -123,8 +118,22 @@ public class SideFragmentManager { mFragmentCount++; if (isFirst) { + // We should wait for fragment transition and intital layouting finished to start the + // slide-in animation to prevent jankiness resulted by performing transition and + // layouting at the same time with animation. mPanel.setVisibility(View.VISIBLE); - mShowAnimator.start(); + mShowOnGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + mPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this); + mShowOnGlobalLayoutListener = null; + if (mPreShowRunnable != null) { + mPreShowRunnable.run(); + } + mShowAnimator.start(); + } + }; + mPanel.getViewTreeObserver().addOnGlobalLayoutListener(mShowOnGlobalLayoutListener); } scheduleHideAll(); } @@ -142,6 +151,18 @@ public class SideFragmentManager { } public void hideAll(boolean withAnimation) { + if (mShowAnimator.isStarted()) { + mShowAnimator.end(); + } + if (mShowOnGlobalLayoutListener != null) { + // The show operation maybe requested but the show animator is not started yet, in this + // case, we show still run mPreShowRunnable. + mPanel.getViewTreeObserver().removeOnGlobalLayoutListener(mShowOnGlobalLayoutListener); + mShowOnGlobalLayoutListener = null; + if (mPreShowRunnable != null) { + mPreShowRunnable.run(); + } + } if (withAnimation) { if (!isHiding()) { mHideAnimator.start(); @@ -178,7 +199,6 @@ public class SideFragmentManager { * @param withAnimation specifies if animation should be shown. */ public void showSidePanel(boolean withAnimation) { - SideFragment.preloadRecycledViews(mActivity); if (mFragmentCount == 0) { return; } diff --git a/src/com/android/tv/ui/sidepanel/SimpleItem.java b/src/com/android/tv/ui/sidepanel/SimpleActionItem.java index 52a5f13f..42553b66 100644 --- a/src/com/android/tv/ui/sidepanel/SimpleItem.java +++ b/src/com/android/tv/ui/sidepanel/SimpleActionItem.java @@ -19,12 +19,12 @@ package com.android.tv.ui.sidepanel; /** * A simple item which shows title and description. */ -public class SimpleItem extends ActionItem { - public SimpleItem(String title) { +public class SimpleActionItem extends ActionItem { + public SimpleActionItem(String title) { super(title); } - public SimpleItem(String title, String description) { + public SimpleActionItem(String title, String description) { super(title, description); } diff --git a/src/com/android/tv/ui/sidepanel/SubMenuItem.java b/src/com/android/tv/ui/sidepanel/SubMenuItem.java index aa349dbd..4b0e8e2c 100644 --- a/src/com/android/tv/ui/sidepanel/SubMenuItem.java +++ b/src/com/android/tv/ui/sidepanel/SubMenuItem.java @@ -21,20 +21,11 @@ public abstract class SubMenuItem extends ActionItem { private final SideFragmentManager mSideFragmentManager; public SubMenuItem(String title, SideFragmentManager fragmentManager) { - this(title, null, 0, fragmentManager); + this(title, null, fragmentManager); } public SubMenuItem(String title, String description, SideFragmentManager fragmentManager) { - this(title, description, 0, fragmentManager); - } - - public SubMenuItem(String title, int iconId, SideFragmentManager fragmentManager) { - this(title, null, iconId, fragmentManager); - } - - public SubMenuItem(String title, String description, int iconId, - SideFragmentManager fragmentManager) { - super(title, description, iconId); + super(title, description); mSideFragmentManager = fragmentManager; } diff --git a/src/com/android/tv/ui/sidepanel/SwitchItem.java b/src/com/android/tv/ui/sidepanel/SwitchItem.java index ef9966a5..06591b62 100644 --- a/src/com/android/tv/ui/sidepanel/SwitchItem.java +++ b/src/com/android/tv/ui/sidepanel/SwitchItem.java @@ -31,6 +31,11 @@ public class SwitchItem extends CompoundButtonItem { super(checkedTitle, uncheckedTitle, description); } + public SwitchItem(String checkedTitle, String uncheckedTitle, String description, + int maxLines) { + super(checkedTitle, uncheckedTitle, description, maxLines); + } + @Override protected int getResourceId() { return R.layout.option_item_switch; diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java index da712924..9a4879fc 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java @@ -130,17 +130,8 @@ public class ParentalControlsFragment extends SideFragment { protected void onSelected() { final MainActivity tvActivity = getMainActivity(); tvActivity.getOverlayManager().getSideFragmentManager().hideSidePanel(true); - - PinDialogFragment fragment = - new PinDialogFragment( - PinDialogFragment.PIN_DIALOG_TYPE_NEW_PIN, - new PinDialogFragment.ResultListener() { - @Override - public void done(boolean success) { - tvActivity.getOverlayManager().getSideFragmentManager() - .showSidePanel(true); - } - }); + PinDialogFragment fragment = PinDialogFragment.create( + PinDialogFragment.PIN_DIALOG_TYPE_NEW_PIN); tvActivity.getOverlayManager().showDialogFragment(PinDialogFragment.DIALOG_TAG, fragment, true); } diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java index 6bc47939..7c8cecbe 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java @@ -17,16 +17,17 @@ package com.android.tv.ui.sidepanel.parentalcontrols; import android.graphics.drawable.Drawable; +import android.media.tv.TvContentRating; import android.os.Bundle; import android.util.ArrayMap; import android.util.SparseIntArray; import android.view.View; import android.widget.CompoundButton; import android.widget.ImageView; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.dialog.WebDialogFragment; +import com.android.tv.experiments.Experiments; import com.android.tv.license.LicenseUtils; import com.android.tv.parental.ContentRatingSystem; import com.android.tv.parental.ContentRatingSystem.Rating; @@ -38,7 +39,6 @@ import com.android.tv.ui.sidepanel.RadioButtonItem; import com.android.tv.ui.sidepanel.SideFragment; import com.android.tv.util.TvSettings; import com.android.tv.util.TvSettings.ContentRatingLevel; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -77,6 +77,7 @@ public class RatingsFragment extends SideFragment { private final List<RatingLevelItem> mRatingLevelItems = new ArrayList<>(); // A map from the rating system ID string to RatingItem objects. private final Map<String, List<RatingItem>> mContentRatingSystemItemMap = new ArrayMap<>(); + private CheckBoxItem mBlockUnratedItem; private ParentalControlSettings mParentalControlSettings; public static String getDescription(MainActivity tvActivity) { @@ -102,6 +103,12 @@ public class RatingsFragment extends SideFragment { protected List<Item> getItemList() { List<Item> items = new ArrayList<>(); + if (mBlockUnratedItem != null + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { + items.add(mBlockUnratedItem); + items.add(new DividerItem()); + } + mRatingLevelItems.clear(); for (int i = 0; i < sLevelResourceIdMap.size(); ++i) { mRatingLevelItems.add(new RatingLevelItem(sLevelResourceIdMap.keyAt(i))); @@ -152,6 +159,28 @@ public class RatingsFragment extends SideFragment { super.onCreate(savedInstanceState); mParentalControlSettings = getMainActivity().getParentalControlSettings(); mParentalControlSettings.loadRatings(); + if (Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { + mBlockUnratedItem = + new CheckBoxItem( + getResources().getString(R.string.option_block_unrated_programs)) { + + @Override + protected void onUpdate() { + super.onUpdate(); + setChecked( + mParentalControlSettings.isRatingBlocked( + new TvContentRating[] {TvContentRating.UNRATED})); + } + + @Override + protected void onSelected() { + super.onSelected(); + if (mParentalControlSettings.setUnratedBlocked(isChecked())) { + updateRatingLevels(); + } + } + }; + } } @Override @@ -202,6 +231,13 @@ public class RatingsFragment extends SideFragment { super.onSelected(); mParentalControlSettings.setContentRatingLevel( getMainActivity().getContentRatingsManager(), mRatingLevel); + if (mBlockUnratedItem != null + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { + // set checked if UNRATED is blocked, and set unchecked otherwise. + mBlockUnratedItem.setChecked( + mParentalControlSettings.isRatingBlocked( + new TvContentRating[] {TvContentRating.UNRATED})); + } notifyItemsChanged(mRatingLevelItems.size()); } } @@ -302,7 +338,7 @@ public class RatingsFragment extends SideFragment { @Override protected void onSelected() { getMainActivity().getOverlayManager().getSideFragmentManager() - .show(new SubRatingsFragment(mContentRatingSystem, mRating)); + .show(SubRatingsFragment.create(mContentRatingSystem, mRating.getName())); } @Override diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/SubRatingsFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/SubRatingsFragment.java index f6612fdb..4634b74c 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/SubRatingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/SubRatingsFragment.java @@ -17,6 +17,7 @@ package com.android.tv.ui.sidepanel.parentalcontrols; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.view.View; import android.widget.CompoundButton; import android.widget.ImageView; @@ -36,13 +37,34 @@ import java.util.List; public class SubRatingsFragment extends SideFragment { private static final String TRACKER_LABEL = "Sub ratings"; - private final ContentRatingSystem mContentRatingSystem; - private final Rating mRating; + private static final String ARGS_CONTENT_RATING_SYSTEM_ID = "args_content_rating_system_id"; + private static final String ARGS_RATING_NAME = "args_rating_name"; + + private ContentRatingSystem mContentRatingSystem; + private Rating mRating; private final List<SubRatingItem> mSubRatingItems = new ArrayList<>(); - public SubRatingsFragment(ContentRatingSystem contentRatingSystem, Rating rating) { - mContentRatingSystem = contentRatingSystem; - mRating = rating; + public static SubRatingsFragment create(ContentRatingSystem contentRatingSystem, + String ratingName) { + SubRatingsFragment fragment = new SubRatingsFragment(); + Bundle args = new Bundle(); + args.putString(ARGS_CONTENT_RATING_SYSTEM_ID, contentRatingSystem.getId()); + args.putString(ARGS_RATING_NAME, ratingName); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContentRatingSystem = getMainActivity().getContentRatingsManager() + .getContentRatingSystem(getArguments().getString(ARGS_CONTENT_RATING_SYSTEM_ID)); + if (mContentRatingSystem != null) { + mRating = mContentRatingSystem.getRating(getArguments().getString(ARGS_RATING_NAME)); + } + if (mRating == null) { + closeFragment(); + } } @Override |