From ad8bb145f00812459b96e54fdaad36f3a7a3612c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christofer=20=C3=85kersten?= Date: Thu, 31 Jul 2014 09:30:11 +0900 Subject: [WIP] Rework sidepanel to make adding options easier. Change-Id: I045e526fe573fec4585e7bf4110569aed09ace79 --- src/com/android/tv/TvActivity.java | 27 +- src/com/android/tv/ui/sidepanel/ActionItem.java | 47 +++ .../tv/ui/sidepanel/BaseOptionFragment.java | 104 ------- src/com/android/tv/ui/sidepanel/CheckBoxItem.java | 67 +++++ .../tv/ui/sidepanel/ClosedCaptionFragment.java | 41 +++ .../ui/sidepanel/ClosedCaptionOptionFragment.java | 92 ------ .../tv/ui/sidepanel/DebugOptionFragment.java | 334 --------------------- .../tv/ui/sidepanel/DisplayModeFragment.java | 30 ++ .../tv/ui/sidepanel/DisplayModeOptionFragment.java | 88 ------ src/com/android/tv/ui/sidepanel/DividerItem.java | 26 ++ .../tv/ui/sidepanel/EditChannelsFragment.java | 219 +++++--------- .../tv/ui/sidepanel/InputPickerFragment.java | 125 ++++---- src/com/android/tv/ui/sidepanel/Item.java | 27 ++ .../tv/ui/sidepanel/PipLocationFragment.java | 108 +++---- .../android/tv/ui/sidepanel/RadioButtonItem.java | 67 +++++ src/com/android/tv/ui/sidepanel/SideFragment.java | 149 +++++++++ src/com/android/tv/ui/sidepanel/SubMenuItem.java | 81 +++++ 17 files changed, 720 insertions(+), 912 deletions(-) create mode 100644 src/com/android/tv/ui/sidepanel/ActionItem.java delete mode 100644 src/com/android/tv/ui/sidepanel/BaseOptionFragment.java create mode 100644 src/com/android/tv/ui/sidepanel/CheckBoxItem.java create mode 100644 src/com/android/tv/ui/sidepanel/ClosedCaptionFragment.java delete mode 100644 src/com/android/tv/ui/sidepanel/ClosedCaptionOptionFragment.java delete mode 100644 src/com/android/tv/ui/sidepanel/DebugOptionFragment.java create mode 100644 src/com/android/tv/ui/sidepanel/DisplayModeFragment.java delete mode 100644 src/com/android/tv/ui/sidepanel/DisplayModeOptionFragment.java create mode 100644 src/com/android/tv/ui/sidepanel/DividerItem.java create mode 100644 src/com/android/tv/ui/sidepanel/Item.java create mode 100644 src/com/android/tv/ui/sidepanel/RadioButtonItem.java create mode 100644 src/com/android/tv/ui/sidepanel/SideFragment.java create mode 100644 src/com/android/tv/ui/sidepanel/SubMenuItem.java (limited to 'src/com') diff --git a/src/com/android/tv/TvActivity.java b/src/com/android/tv/TvActivity.java index 0e0c6b28..b5671bfc 100644 --- a/src/com/android/tv/TvActivity.java +++ b/src/com/android/tv/TvActivity.java @@ -70,15 +70,19 @@ import com.android.tv.ui.KeypadView; import com.android.tv.ui.MainMenuView; import com.android.tv.ui.TunableTvView; import com.android.tv.ui.TunableTvView.OnTuneListener; +import com.android.tv.ui.sidepanel.ActionItem; import com.android.tv.ui.sidepanel.BaseSideFragment; -import com.android.tv.ui.sidepanel.ClosedCaptionOptionFragment; -import com.android.tv.ui.sidepanel.DebugOptionFragment; -import com.android.tv.ui.sidepanel.DisplayModeOptionFragment; +import com.android.tv.ui.sidepanel.ClosedCaptionFragment; +import com.android.tv.ui.sidepanel.DisplayModeFragment; import com.android.tv.ui.sidepanel.EditChannelsFragment; import com.android.tv.ui.sidepanel.InputPickerFragment; +import com.android.tv.ui.sidepanel.Item; import com.android.tv.ui.sidepanel.PipLocationFragment; +import com.android.tv.ui.sidepanel.RadioButtonItem; +import com.android.tv.ui.sidepanel.SideFragment; import com.android.tv.ui.sidepanel.SidePanelContainer; import com.android.tv.ui.sidepanel.SimpleGuideFragment; +import com.android.tv.ui.sidepanel.SubMenuItem; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.TvSettings; import com.android.tv.util.Utils; @@ -554,11 +558,11 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha } public void showDisplayModeOption(int initiator) { - showSideFragment(new DisplayModeOptionFragment(), initiator); + showSideFragment(new DisplayModeFragment(), initiator); } public void showClosedCaptionOption(int initiator) { - showSideFragment(new ClosedCaptionOptionFragment(), initiator); + showSideFragment(new ClosedCaptionFragment(), initiator); } public void showPipLocationOption(int initiator) { @@ -566,13 +570,18 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha } public void showDebugOptions(int initiator) { - showSideFragment(new DebugOptionFragment() { + showSideFragment(new SideFragment() { @Override - protected List buildItems() { + protected String getTitle() { + return getString(R.string.menu_debug_options); + } + + @Override + protected List getItemList() { List items = new ArrayList<>(); items.add(new SubMenuItem(getString(R.string.item_tv_input), getFragmentManager()) { @Override - protected List buildItems() { + protected List getItemList() { return getTvInputMenu(); } }); @@ -1221,7 +1230,7 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha } case KeyEvent.KEYCODE_D: - showDebugOptions(BaseSideFragment.INITIATOR_UNKNOWN); + showDebugOptions(BaseSideFragment.INITIATOR_SHORTCUT_KEY); return true; case KeyEvent.KEYCODE_K: diff --git a/src/com/android/tv/ui/sidepanel/ActionItem.java b/src/com/android/tv/ui/sidepanel/ActionItem.java new file mode 100644 index 00000000..1ef862cd --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/ActionItem.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 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.view.View; +import android.widget.TextView; + +import com.android.tv.R; + +public class ActionItem extends Item { + private final String mTitle; + private TextView mTitleView; + + public ActionItem(String title) { + mTitle = title; + } + + @Override + protected int getResourceId() { + return R.layout.option_item_action; + } + + @Override + protected void bind(View view) { + mTitleView = (TextView) view.findViewById(R.id.title); + mTitleView.setText(mTitle); + } + + @Override + protected void unbind() { + mTitleView = null; + } +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/BaseOptionFragment.java b/src/com/android/tv/ui/sidepanel/BaseOptionFragment.java deleted file mode 100644 index b8d45acc..00000000 --- a/src/com/android/tv/ui/sidepanel/BaseOptionFragment.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2014 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.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RadioButton; - -import com.android.tv.R; -import com.android.tv.TvActivity; - -public class BaseOptionFragment extends BaseSideFragment { - private static final String TAG = "ClosedCaptionOptionFragment"; - private static final boolean DEBUG = true; - - private View mMainView; - private boolean mClosingByItemSelected; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mMainView = super.onCreateView(inflater, container, savedInstanceState); - return mMainView; - } - - @Override - public void onDetach() { - super.onDetach(); - if (!mClosingByItemSelected) { - ((TvActivity) getActivity()).onSideFragmentCanceled(getInitiator()); - } - ((TvActivity) getActivity()).hideOverlays(false, false, true); - } - - @Override - public final void initialize(String title, Object[] itemTags, int fragmentLayoutId, - int itemLayoutId, int itemBgColor, int itemFocusedBgColor, int itemHeightResId) { - throw new UnsupportedOperationException("Call initialize(String title, Object[] itemTags)"); - } - - public void initialize(String title, Object[] itemTags) { - super.initialize(title, itemTags, R.layout.option_fragment, R.layout.option_item, - R.color.option_item_background, R.color.option_item_focused_background, - R.dimen.option_item_height); - } - - public void initialize(String title, int itemLayoutResId, Object[] itemTags) { - super.initialize(title, itemTags, R.layout.option_fragment, itemLayoutResId, - R.color.option_item_background, R.color.option_item_focused_background, - R.dimen.option_item_height); - } - - @Override - public void onItemSelected(View v, int position, Object tag) { - RadioButton radioButton = (RadioButton) v.findViewById(R.id.option_item); - uncheckAllRadioButtons((ViewGroup) mMainView); - radioButton.setChecked(true); - mClosingByItemSelected = true; - ((TvActivity) getActivity()).popFragmentBackStack(); - } - - @Override - public void onBindView(View v, int position, Object tag, boolean prevSelected) { - RadioButton radioButton = (RadioButton) v.findViewById(R.id.option_item); - if (prevSelected) { - radioButton.setChecked(true); - } else { - radioButton.setChecked(false); - } - if (tag instanceof String) { - radioButton.setText((String) tag); - } else { - radioButton.setText(""); - } - } - - private static void uncheckAllRadioButtons(ViewGroup parent) { - int count = parent.getChildCount(); - for (int i = 0; i < count; ++i) { - View v = parent.getChildAt(i); - if (v instanceof ViewGroup) { - uncheckAllRadioButtons((ViewGroup) v); - } else if (v instanceof RadioButton) { - ((RadioButton) v).setChecked(false); - } - } - } -} diff --git a/src/com/android/tv/ui/sidepanel/CheckBoxItem.java b/src/com/android/tv/ui/sidepanel/CheckBoxItem.java new file mode 100644 index 00000000..f61a5554 --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/CheckBoxItem.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 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.view.View; +import android.widget.CheckBox; + +import com.android.tv.R; + +public class CheckBoxItem extends Item { + private final String mTitle; + private boolean mChecked; + private CheckBox mCheckBox; + + public CheckBoxItem(String title) { + mTitle = title; + } + + @Override + protected int getResourceId() { + return R.layout.option_item_check_box; + } + + @Override + protected void bind(View view) { + mCheckBox = (CheckBox) view.findViewById(R.id.check_box); + mCheckBox.setText(mTitle); + mCheckBox.setChecked(mChecked); + } + + @Override + protected void unbind() { + mCheckBox = null; + } + + @Override + protected void onSelected() { + setChecked(!mChecked); + } + + public void setChecked(boolean checked) { + if (mChecked != checked) { + mChecked = checked; + if (mCheckBox != null) { + mCheckBox.setChecked(mChecked); + } + } + } + + public boolean getChecked() { + return mChecked; + } +} \ 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 new file mode 100644 index 00000000..45693d1b --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/ClosedCaptionFragment.java @@ -0,0 +1,41 @@ +package com.android.tv.ui.sidepanel; + +import android.widget.Toast; + +import com.android.tv.R; + +import java.util.ArrayList; +import java.util.List; + +public class ClosedCaptionFragment extends SideFragment { + @Override + protected String getTitle() { + return getString(R.string.closed_caption_option_title); + } + + @Override + protected List getItemList() { + ArrayList items = new ArrayList<>(); + items.add(new RadioButtonItem(getString(R.string.option_item_on)) { + @Override + protected void onSelected() { + super.onSelected(); + getTvActivity().setClosedCaptionEnabled(false, true); + setClosedCaptionEnabled(true); + } + }); + items.add(new RadioButtonItem(getString(R.string.option_item_off)) { + @Override + protected void onSelected() { + super.onSelected(); + setClosedCaptionEnabled(false); + } + }); + return items; + } + + private void setClosedCaptionEnabled(boolean enabled) { + getTvActivity().setClosedCaptionEnabled(enabled, true); + Toast.makeText(getActivity(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show(); + } +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/ClosedCaptionOptionFragment.java b/src/com/android/tv/ui/sidepanel/ClosedCaptionOptionFragment.java deleted file mode 100644 index 3db185ff..00000000 --- a/src/com/android/tv/ui/sidepanel/ClosedCaptionOptionFragment.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2014 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.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Toast; - -import com.android.tv.R; -import com.android.tv.TvActivity; - -public class ClosedCaptionOptionFragment extends BaseOptionFragment { - private static final String TAG = "ClosedCaptionOptionFragment"; - private static final boolean DEBUG = true; - - private static final int CC_ON = 0; - private static final int CC_OFF = 1; - - private TvActivity mTvActivity; - private boolean mIsFirstResume; - private boolean mLastStoredCcEnabled; - private boolean mCcEnabled; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mIsFirstResume = true; - mTvActivity = (TvActivity) getActivity(); - - Object[] items = new Object[2]; - items[0] = getString(R.string.option_item_on); - items[1] = getString(R.string.option_item_off); - - initialize(getString(R.string.closed_caption_option_title), items); - return super.onCreateView(inflater, container, savedInstanceState); - } - - @Override - public void onResume() { - super.onResume(); - if (mIsFirstResume) { - mCcEnabled = mTvActivity.isClosedCaptionEnabled(); - mLastStoredCcEnabled = mCcEnabled; - int initialPosition = mCcEnabled ? CC_ON : CC_OFF; - setSelectedPosition(initialPosition); - setPrevSelectedItemPosition(initialPosition); - mIsFirstResume = false; - } - } - - @Override - public void onDetach() { - super.onDetach(); - if (mLastStoredCcEnabled != mCcEnabled) { - mTvActivity.restoreClosedCaptionEnabled(); - } - } - - @Override - public void onItemFocusChanged(View v, boolean focusGained, int position, Object tag) { - super.onItemFocusChanged(v, focusGained, position, tag); - if (focusGained) { - mCcEnabled = (position == CC_ON); - mTvActivity.setClosedCaptionEnabled(mCcEnabled, false); - } - } - - @Override - public void onItemSelected(View v, int position, Object tag) { - mCcEnabled = (position == CC_ON); - mTvActivity.setClosedCaptionEnabled(mCcEnabled, true); - mLastStoredCcEnabled = mCcEnabled; - super.onItemSelected(v, position, tag); - Toast.makeText(getActivity(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show(); - } -} diff --git a/src/com/android/tv/ui/sidepanel/DebugOptionFragment.java b/src/com/android/tv/ui/sidepanel/DebugOptionFragment.java deleted file mode 100644 index 70641361..00000000 --- a/src/com/android/tv/ui/sidepanel/DebugOptionFragment.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 2014 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.app.FragmentManager; -import android.app.FragmentTransaction; -import android.os.Bundle; -import android.support.v17.leanback.widget.VerticalGridView; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.RadioButton; -import android.widget.TextView; - -import com.android.tv.R; -import com.android.tv.TvActivity; - -import java.util.List; - -public class DebugOptionFragment extends BaseSideFragment { - private final boolean mSubOption; - private final String mHeader; - private final List mItems; - - public DebugOptionFragment() { - mSubOption = false; - mHeader = null; - mItems = null; - } - - private DebugOptionFragment(String header, List items) { - mSubOption = true; - mHeader = header; - mItems = items; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - initialize(mHeader == null ? getString(R.string.menu_debug_options) : mHeader, null, - R.layout.option_fragment, 0, R.color.option_item_background, - R.color.option_item_focused_background, R.dimen.option_item_height); - View view = super.onCreateView(inflater, container, savedInstanceState); - VerticalGridView listView = (VerticalGridView) view.findViewById(R.id.side_panel_list); - listView.setAdapter(new ItemAdapter(inflater, mItems == null ? buildItems() : mItems)); - setSelectedPosition(0); - if (mSubOption) { - view.findViewById(R.id.side_panel_shadow).setVisibility(View.GONE); - } - return view; - } - - @Override - public void onDetach() { - super.onDetach(); - if (!mSubOption) { - getTvActivity().onSideFragmentCanceled(getInitiator()); - getTvActivity().hideOverlays(false, false, true); - } - } - - protected List buildItems() { - return null; - } - - private TvActivity getTvActivity() { - return (TvActivity) getActivity(); - } - - public static abstract class Item { - protected abstract int getResourceId(); - protected void bind(@SuppressWarnings("unused") View view) { } - protected void unbind() { } - protected void onSelected() { } - protected void onFocused() { } - } - - public static class DividerItem extends Item { - @Override - protected int getResourceId() { - return R.layout.debug_option_divider; - } - } - - public static class ActionItem extends Item { - private final String mTitle; - private TextView mTitleView; - - public ActionItem(String title) { - mTitle = title; - } - - @Override - protected int getResourceId() { - return R.layout.debug_option_action; - } - - @Override - protected void bind(View view) { - mTitleView = (TextView) view.findViewById(R.id.title); - mTitleView.setText(mTitle); - } - - @Override - protected void unbind() { - mTitleView = null; - } - } - - public static class SubMenuItem extends Item { - private final String mTitle; - private final FragmentManager mFragmentManager; - private TextView mTitleView; - - public SubMenuItem(String title, FragmentManager fragmentManager) { - mTitle = title; - mFragmentManager = fragmentManager; - } - - @Override - protected int getResourceId() { - return R.layout.debug_option_sub_menu; - } - - @Override - protected void bind(View view) { - mTitleView = (TextView) view.findViewById(R.id.title); - mTitleView.setText(mTitle); - } - - @Override - protected void unbind() { - mTitleView = null; - } - - @Override - protected void onSelected() { - mFragmentManager - .beginTransaction() - .add(R.id.right_panel, new DebugOptionFragment(mTitle, buildItems())) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) - .commit(); - } - - protected List buildItems() { - return null; - } - } - - public static class CheckBoxItem extends Item { - private final String mTitle; - private boolean mChecked; - private CheckBox mCheckBox; - - public CheckBoxItem(String title) { - mTitle = title; - } - - @Override - protected int getResourceId() { - return R.layout.debug_option_check_box; - } - - @Override - protected void bind(View view) { - mCheckBox = (CheckBox) view.findViewById(R.id.check_box); - mCheckBox.setText(mTitle); - mCheckBox.setChecked(mChecked); - } - - @Override - protected void unbind() { - mCheckBox = null; - } - - @Override - protected void onSelected() { - setChecked(!mChecked); - } - - public void setChecked(boolean checked) { - if (mChecked != checked) { - mChecked = checked; - if (mCheckBox != null) { - mCheckBox.setChecked(mChecked); - } - } - } - } - - public static class RadioButtonItem extends Item { - private final String mTitle; - private boolean mChecked; - private RadioButton mRadioButton; - - public RadioButtonItem(String title) { - mTitle = title; - } - - @Override - protected int getResourceId() { - return R.layout.debug_option_radio_button; - } - - @Override - protected void bind(View view) { - mRadioButton = (RadioButton) view.findViewById(R.id.radio_button); - mRadioButton.setText(mTitle); - mRadioButton.setChecked(mChecked); - } - - @Override - protected void unbind() { - mRadioButton = null; - } - - @Override - protected void onSelected() { - setChecked(true); - } - - public void setChecked(boolean checked) { - if (mChecked != checked) { - mChecked = checked; - if (mRadioButton != null) { - mRadioButton.setChecked(mChecked); - } - } - } - } - - private static class ItemAdapter extends RecyclerView.Adapter { - private final LayoutInflater mLayoutInflater; - private final List mItems; - - private ItemAdapter(LayoutInflater layoutInflater, List items) { - mLayoutInflater = layoutInflater; - mItems = items; - } - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = mLayoutInflater.inflate(viewType, parent, false); - final ViewHolder holder = new ViewHolder(view); - view.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (holder.item instanceof RadioButtonItem) { - clearRadioGroup(holder.item); - } - holder.item.onSelected(); - } - }); - view.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View view, boolean focusGained) { - if (focusGained) { - holder.item.onFocused(); - } - } - }); - return holder; - } - - @Override - public void onBindViewHolder(ViewHolder holder, int position) { - holder.item = getItem(position); - holder.item.bind(holder.itemView); - } - - @Override - public void onViewRecycled(ViewHolder holder) { - holder.item.unbind(); - holder.item = null; - } - - @Override - public int getItemViewType(int position) { - return getItem(position).getResourceId(); - } - - @Override - public int getItemCount() { - return mItems == null ? 0 : mItems.size(); - } - - private Item getItem(int position) { - return mItems.get(position); - } - - private void clearRadioGroup(Item item) { - int position = mItems.indexOf(item); - for (int i = position - 1; i >= 0; --i) { - if ((item = mItems.get(i)) instanceof RadioButtonItem) { - ((RadioButtonItem) item).setChecked(false); - } else { - break; - } - } - for (int i = position + 1; i < mItems.size(); ++i) { - if ((item = mItems.get(i)) instanceof RadioButtonItem) { - ((RadioButtonItem) item).setChecked(false); - } else { - break; - } - } - } - - private static class ViewHolder extends RecyclerView.ViewHolder { - public Item item; - - private ViewHolder(View view) { - super(view); - } - } - } -} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/DisplayModeFragment.java b/src/com/android/tv/ui/sidepanel/DisplayModeFragment.java new file mode 100644 index 00000000..120ef9e3 --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/DisplayModeFragment.java @@ -0,0 +1,30 @@ +package com.android.tv.ui.sidepanel; + +import com.android.tv.R; +import com.android.tv.data.DisplayMode; + +import java.util.ArrayList; +import java.util.List; + +public class DisplayModeFragment extends SideFragment { + @Override + protected String getTitle() { + return getString(R.string.display_mode_option_title); + } + + @Override + protected List getItemList() { + ArrayList items = new ArrayList<>(); + for (int i = 0; i < DisplayMode.SIZE_OF_RATIO_TYPES; ++i) { + final int displayMode = i; + items.add(new RadioButtonItem(DisplayMode.getLabel(i, getActivity())) { + @Override + protected void onSelected() { + super.onSelected(); + getTvActivity().setDisplayMode(displayMode, true); + } + }); + } + return items; + } +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/DisplayModeOptionFragment.java b/src/com/android/tv/ui/sidepanel/DisplayModeOptionFragment.java deleted file mode 100644 index 43b446d4..00000000 --- a/src/com/android/tv/ui/sidepanel/DisplayModeOptionFragment.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2014 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.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.android.tv.R; -import com.android.tv.TvActivity; -import com.android.tv.data.DisplayMode; - -public class DisplayModeOptionFragment extends BaseOptionFragment { - private static final String TAG = "AspectRatioOptionFragment"; - private static final boolean DEBUG = true; - - private TvActivity mTvActivity; - private boolean mIsFirstResume; - private int mLastStoredAspectRatio; - private int mAspectRatio; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mIsFirstResume = true; - mTvActivity = (TvActivity) getActivity(); - - Object[] items = new Object[DisplayMode.SIZE_OF_RATIO_TYPES]; - for (int i = 0; i < DisplayMode.SIZE_OF_RATIO_TYPES; ++i) { - items[i] = DisplayMode.getLabel(i, getActivity()); - } - initialize(getString(R.string.display_mode_option_title), items); - return super.onCreateView(inflater, container, savedInstanceState); - } - - @Override - public void onResume() { - super.onResume(); - if (mIsFirstResume) { - mAspectRatio = mTvActivity.getDisplayMode(); - mLastStoredAspectRatio = mAspectRatio; - int initialPosition = mAspectRatio; - setSelectedPosition(initialPosition); - setPrevSelectedItemPosition(initialPosition); - mIsFirstResume = false; - } - } - - @Override - public void onDetach() { - super.onDetach(); - if (mLastStoredAspectRatio != mAspectRatio) { - mTvActivity.restoreDisplayMode(); - } - } - - @Override - public void onItemFocusChanged(View v, boolean focusGained, int position, Object tag) { - super.onItemFocusChanged(v, focusGained, position, tag); - if (focusGained) { - mAspectRatio = position; - mTvActivity.setDisplayMode(position, false); - } - } - - @Override - public void onItemSelected(View v, int position, Object tag) { - mAspectRatio = position; - mTvActivity.setDisplayMode(mAspectRatio, true); - mLastStoredAspectRatio = mAspectRatio; - super.onItemSelected(v, position, tag); - } -} diff --git a/src/com/android/tv/ui/sidepanel/DividerItem.java b/src/com/android/tv/ui/sidepanel/DividerItem.java new file mode 100644 index 00000000..019e6454 --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/DividerItem.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014 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 com.android.tv.R; + +public class DividerItem extends Item { + @Override + protected int getResourceId() { + return R.layout.option_item_divider; + } +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/EditChannelsFragment.java b/src/com/android/tv/ui/sidepanel/EditChannelsFragment.java index 48d21fd3..2497630b 100644 --- a/src/com/android/tv/ui/sidepanel/EditChannelsFragment.java +++ b/src/com/android/tv/ui/sidepanel/EditChannelsFragment.java @@ -19,191 +19,110 @@ package com.android.tv.ui.sidepanel; import android.content.ContentValues; import android.media.tv.TvContract; import android.net.Uri; -import android.os.Bundle; import android.text.TextUtils; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.TextView; import android.widget.Toast; -import com.android.internal.util.Preconditions; import com.android.tv.R; -import com.android.tv.TvActivity; import com.android.tv.data.Channel; -import com.android.tv.input.TvInput; - -public class EditChannelsFragment extends BaseSideFragment { - private static final int ACTION_SHOW_ALL = 0; - private static final int ACTION_HIDE_ALL = 1; - - private TvInput mSelectedInput; - - private TvActivity mTvActivity; - private Item[] mItems; - private String[] mActions; - private Channel[] mChannels; - private int mBrowsableChannelCount; - - private static final class Item { - private static final int TYPE_ACTION = 0; - private static final int TYPE_CHANNEL = 1; - private static final int TYPE_DIVIDER = 2; - - private Item(int type, int action, Channel channel) { - mType = type; - mAction = action; - Preconditions.checkState(!(type == TYPE_CHANNEL && channel == null)); - mChannel = channel; - } - private int mType; - private int mAction; - private Channel mChannel; - } +import java.util.ArrayList; +import java.util.List; + +public class EditChannelsFragment extends SideFragment { + Channel[] mChannels; public EditChannelsFragment(Channel[] channels) { mChannels = channels; - mBrowsableChannelCount = 0; - for (Channel channel : channels) { - if (channel.isBrowsable()) { - ++mBrowsableChannelCount; - } - } } @Override - public void onDetach() { - super.onDetach(); - mTvActivity.onSideFragmentCanceled(getInitiator()); - mTvActivity.hideOverlays(false, false, true); + protected String getTitle() { + String displayName = getTvActivity().getSelectedTvInput().getDisplayName(); + return String.format(getString(R.string.edit_channels_title), displayName); } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mTvActivity = (TvActivity) getActivity(); - mSelectedInput = mTvActivity.getSelectedTvInput(); - - mActions = getActivity().getResources().getStringArray(R.array.edit_channels_actions); - mItems = new Item[mActions.length + mChannels.length + 1]; - int index = 0; - for (; index < mActions.length; ++index) { - mItems[index] = new Item(Item.TYPE_ACTION, index ,null); - } - mItems[index++] = new Item(Item.TYPE_DIVIDER, 0, null); + protected List getItemList() { + ArrayList items = new ArrayList<>(); + items.add(new ActionItem(getString(R.string.edit_channels_show_all)) { + @Override + protected void onSelected() { + super.onSelected(); + updateAllChannels(true); + } + }); + items.add(new ActionItem(getString(R.string.edit_channels_hide_all)) { + @Override + protected void onSelected() { + super.onSelected(); + updateAllChannels(false); + } + }); + items.add(new DividerItem()); for (Channel channel : mChannels) { - mItems[index++] = new Item(Item.TYPE_CHANNEL, 0, channel); + final Channel currentChannel = channel; + items.add(new CheckBoxItem(getChannelName(channel)) { + @Override + protected void bind(View view) { + super.bind(view); + setChecked(currentChannel.isBrowsable()); + } + + @Override + protected void onSelected() { + super.onSelected(); + + Uri uri = TvContract.buildChannelUri(currentChannel.getId()); + ContentValues values = new ContentValues(); + values.put(TvContract.Channels.COLUMN_BROWSABLE, getChecked() ? 1 : 0); + getActivity().getContentResolver().update(uri, values, null, null); + + currentChannel.setBrowsable(getChecked()); + if (!getChecked()) { + maybeDisplayAllUnchecked(); + } + } + }); } - String displayName = mSelectedInput.getDisplayName(); - String title = String.format(getString(R.string.edit_channels_title), displayName); - initialize(title, mItems, R.layout.option_fragment, R.layout.edit_channels_item, - R.color.option_item_background, R.color.option_item_focused_background, - R.dimen.edit_channels_item_height); + return items; + } - if (mBrowsableChannelCount <= 0) { + private void maybeDisplayAllUnchecked() { + if (!hasBrowsableChannel()) { Toast.makeText(getActivity(), R.string.all_the_channels_are_unchecked, Toast.LENGTH_SHORT).show(); } - - return super.onCreateView(inflater, container, savedInstanceState); - } - - @Override - public void onResume() { - super.onResume(); - // TODO: the current channel should be initially focused. - setSelectedPosition(0); - } - - @Override - public void onBindView(View v, int position, Object tag, boolean prevSelected) { - super.onBindView(v, position, tag, prevSelected); - - CheckBox checkBox = (CheckBox) v.findViewById(R.id.check_box); - TextView textView = (TextView) v.findViewById(R.id.channel_text_view); - View itemContainer = v.findViewById(R.id.item_container); - View divider = v.findViewById(R.id.divider); - - Item item = (Item) tag; - if (item.mType == Item.TYPE_ACTION) { - checkBox.setVisibility(View.GONE); - textView.setText(mActions[item.mAction]); - } else if (item.mType == Item.TYPE_CHANNEL) { - checkBox.setVisibility(View.VISIBLE); - checkBox.setChecked(item.mChannel.isBrowsable()); - - String channelNumber = item.mChannel.getDisplayNumber(); - String channelName = item.mChannel.getDisplayName(); - String channelString; - if (TextUtils.isEmpty(channelName)) { - channelString = channelNumber; - } else { - channelString = String.format(getString(R.string.channel_item), - channelNumber, channelName); - } - textView.setText(channelString); - } - divider.setVisibility(item.mType == Item.TYPE_DIVIDER ? View.VISIBLE : View.GONE); - itemContainer.setVisibility(item.mType != Item.TYPE_DIVIDER ? View.VISIBLE : View.GONE); - v.setFocusable(item.mType != Item.TYPE_DIVIDER); - } - - @Override - public void onItemSelected(View v, int position, Object tag) { - Item item = (Item) tag; - if (item.mType == Item.TYPE_ACTION) { - if (item.mAction == ACTION_SHOW_ALL) { - updateAllChannels(true); - } else if (item.mAction == ACTION_HIDE_ALL) { - updateAllChannels(false); - } - } else if (item.mType == Item.TYPE_CHANNEL) { - CheckBox checkBox = (CheckBox) v.findViewById(R.id.check_box); - boolean checked = checkBox.isChecked(); - - Channel channel = item.mChannel; - Uri uri = TvContract.buildChannelUri(channel.getId()); - ContentValues values = new ContentValues(); - values.put(TvContract.Channels.COLUMN_BROWSABLE, checked ? 0 : 1); - getActivity().getContentResolver().update(uri, values, null, null); - channel.setBrowsable(!checked); - - checkBox.setChecked(!checked); - mBrowsableChannelCount += checked ? -1 : 1; - if (mBrowsableChannelCount <= 0) { - Toast.makeText(getActivity(), R.string.all_the_channels_are_unchecked, - Toast.LENGTH_SHORT).show(); - } - } - - super.onItemSelected(v, position, tag); } private void updateAllChannels(boolean browsable) { - Uri uri = mSelectedInput.buildChannelsUri(null); + Uri uri = getTvActivity().getSelectedTvInput().buildChannelsUri(null); ContentValues values = new ContentValues(); values.put(TvContract.Channels.COLUMN_BROWSABLE, browsable ? 1 : 0); - getActivity().getContentResolver().update(uri, values, null, null); for (Channel channel : mChannels) { channel.setBrowsable(browsable); } notifyDataSetChanged(); + maybeDisplayAllUnchecked(); + } - if (browsable) { - mBrowsableChannelCount = mChannels.length; - } else { - mBrowsableChannelCount = 0; - Toast.makeText(getActivity(), R.string.all_the_channels_are_unchecked, - Toast.LENGTH_SHORT).show(); + private boolean hasBrowsableChannel() { + for (Channel channel : mChannels) { + if (channel.isBrowsable()) { + return true; + } } + return false; } - @Override - public void onItemFocusChanged(View v, boolean focusGained, int position, Object tag) { - super.onItemFocusChanged(v, focusGained, position, tag); + private String getChannelName(Channel channel) { + String channelName = channel.getDisplayName(); + String channelNumber = channel.getDisplayNumber(); + if (TextUtils.isEmpty(channelName)) { + return channelNumber; + } + return String.format(getString(R.string.channel_item), channelNumber, channelName); } -} +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/InputPickerFragment.java b/src/com/android/tv/ui/sidepanel/InputPickerFragment.java index 8a05cc1e..ffd48793 100644 --- a/src/com/android/tv/ui/sidepanel/InputPickerFragment.java +++ b/src/com/android/tv/ui/sidepanel/InputPickerFragment.java @@ -17,99 +17,80 @@ package com.android.tv.ui.sidepanel; import android.media.tv.TvInputInfo; -import android.media.tv.TvInputManager; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RadioButton; -import com.android.internal.util.Preconditions; import com.android.tv.R; -import com.android.tv.TvActivity; import com.android.tv.input.TisTvInput; import com.android.tv.input.TvInput; import com.android.tv.input.UnifiedTvInput; -import com.android.tv.util.TvInputManagerHelper; +import com.android.tv.util.Utils; -import java.util.Arrays; -import java.util.Collection; +import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; +import java.util.List; -public class InputPickerFragment extends BaseOptionFragment { - private TvInput mSelectedInput; - - private TvActivity mTvActivity; - private boolean mIsFirstResume; - private int mInitialPosition; - - private TvInputManagerHelper mInputManager; +public class InputPickerFragment extends SideFragment { + @Override + protected String getTitle() { + return getString(R.string.select_input_device); + } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mIsFirstResume = true; - mTvActivity = (TvActivity) getActivity(); - mInputManager = mTvActivity.getTvInputManagerHelper(); - mInputManager.update(); - Collection inputInfos = mInputManager.getTvInputInfos(false); - int inputSize = inputInfos.size(); - Preconditions.checkState(inputSize > 0); - mSelectedInput = mTvActivity.getSelectedTvInput(); + protected List getItemList() { + ArrayList items = new ArrayList<>(); - Object[] items = new Object[inputSize + 1]; - // Unified TV input is always the first item. - items[0] = new UnifiedTvInput(mInputManager, getActivity()); - int i = 1; - for (TvInputInfo inputInfo : inputInfos) { - items[i++] = new TisTvInput(mInputManager, inputInfo, mTvActivity); - } - Arrays.sort(items, 1, items.length, new Comparator() { + items.add(new TvInputItem( + new UnifiedTvInput(getTvActivity().getTvInputManagerHelper(), getActivity()))); + + getTvActivity().getTvInputManagerHelper().update(); + List infos = new ArrayList<>( + getTvActivity().getTvInputManagerHelper().getTvInputInfos(false)); + Collections.sort(infos, new Comparator() { @Override - public int compare(Object lhs, Object rhs) { - return ((TvInput) lhs).getDisplayName().compareTo(((TvInput) rhs).getDisplayName()); + public int compare(TvInputInfo lhs, TvInputInfo rhs) { + String a = Utils.getDisplayNameForInput(getActivity(), lhs); + String b = Utils.getDisplayNameForInput(getActivity(), rhs); + return a.compareTo(b); } }); - - mInitialPosition = 0; - for (i = 0; i < items.length; ++i) { - if (items[i].equals(mSelectedInput)) { - mInitialPosition = i; - break; + for (TvInputInfo inputInfo : infos) { + if (inputInfo.getType() == TvInputInfo.TYPE_TUNER) { + items.add(new TvInputItem(new TisTvInput( + getTvActivity().getTvInputManagerHelper(), inputInfo, getActivity()))); } } - initialize(getString(R.string.select_input_device), items); - return super.onCreateView(inflater, container, savedInstanceState); - } - @Override - public void onResume() { - super.onResume(); - if (mIsFirstResume) { - setSelectedPosition(mInitialPosition); - setPrevSelectedItemPosition(mInitialPosition); - mIsFirstResume = false; + TvInput selected = getTvActivity().getSelectedTvInput(); + if (selected == null) { + ((TvInputItem) items.get(0)).setChecked(true); + } else { + for (Item item : items) { + if (((TvInputItem) item).getTvInput().equals(selected)) { + ((TvInputItem) item).setChecked(true); + break; + } + } } + + return items; } - @Override - public void onBindView(View v, int position, Object tag, boolean prevSelected) { - super.onBindView(v, position, tag, prevSelected); - TvInput input = (TvInput) tag; - boolean available = input.getInputState() != TvInputManager.INPUT_STATE_DISCONNECTED; - v.setEnabled(available); - v.setClickable(available); + private class TvInputItem extends RadioButtonItem { + private TvInput mTvInput; - RadioButton radioButton = (RadioButton) v.findViewById(R.id.option_item); - radioButton.setEnabled(available); - radioButton.setText(input.getDisplayName()); - } + private TvInputItem(TvInput tvInput) { + super(tvInput.getDisplayName()); + mTvInput = tvInput; + } - @Override - public void onItemSelected(View v, int position, Object tag) { - if (!((TvInput) tag).equals(mSelectedInput)) { - mTvActivity.onInputPicked((TvInput) tag); + public TvInput getTvInput() { + return mTvInput; + } + + @Override + protected void onSelected() { + super.onSelected(); + getTvActivity().onInputPicked(mTvInput); } - super.onItemSelected(v, position, tag); } -} +} \ 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 new file mode 100644 index 00000000..53238fd7 --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/Item.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 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.view.View; + +public abstract class Item { + protected abstract int getResourceId(); + protected void bind(@SuppressWarnings("unused") View view) { } + protected void unbind() { } + protected void onSelected() { } + protected void onFocused() { } +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/PipLocationFragment.java b/src/com/android/tv/ui/sidepanel/PipLocationFragment.java index 23c97274..f901d702 100644 --- a/src/com/android/tv/ui/sidepanel/PipLocationFragment.java +++ b/src/com/android/tv/ui/sidepanel/PipLocationFragment.java @@ -16,81 +16,63 @@ package com.android.tv.ui.sidepanel; -import android.os.Bundle; -import android.view.LayoutInflater; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.view.Gravity; import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; +import android.widget.RadioButton; import com.android.tv.R; -import com.android.tv.TvActivity; import com.android.tv.util.TvSettings; -public class PipLocationFragment extends BaseOptionFragment { - private static final String TAG = "PipLocationFragment"; - private static final boolean DEBUG = true; - - private TvActivity mTvActivity; - private boolean mIsFirstResume; - private int mPipLocation; - private final int[] mLocationToItemPosition = new int[4]; - private final Object[] mItem = new Integer[] { - TvSettings.PIP_LOCATION_BOTTOM_RIGHT, - TvSettings.PIP_LOCATION_TOP_RIGHT, - TvSettings.PIP_LOCATION_TOP_LEFT, - TvSettings.PIP_LOCATION_BOTTOM_LEFT, - }; +import java.util.ArrayList; +import java.util.List; +public class PipLocationFragment extends SideFragment { @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mIsFirstResume = true; - mTvActivity = (TvActivity) getActivity(); - - mLocationToItemPosition[TvSettings.PIP_LOCATION_BOTTOM_RIGHT] = 0; - mLocationToItemPosition[TvSettings.PIP_LOCATION_TOP_RIGHT] = 1; - mLocationToItemPosition[TvSettings.PIP_LOCATION_TOP_LEFT] = 2; - mLocationToItemPosition[TvSettings.PIP_LOCATION_BOTTOM_LEFT] = 3; - - initialize(getString(R.string.pip_location_option_title), - R.layout.pip_location_item, mItem); - return super.onCreateView(inflater, container, savedInstanceState); + protected String getTitle() { + return getString(R.string.pip_location_option_title); } @Override - public void onResume() { - super.onResume(); - if (mIsFirstResume) { - mPipLocation = mTvActivity.getPipLocation(); - int initialPosition = mLocationToItemPosition[mPipLocation]; - setSelectedPosition(initialPosition); - setPrevSelectedItemPosition(initialPosition); - mIsFirstResume = false; - } + protected List getItemList() { + ArrayList items = new ArrayList<>(); + items.add(new PipLocationRadio( + TvSettings.PIP_LOCATION_TOP_LEFT, R.drawable.ic_pip_loc_top_left)); + items.add(new PipLocationRadio( + TvSettings.PIP_LOCATION_TOP_RIGHT, R.drawable.ic_pip_loc_top_right)); + items.add(new PipLocationRadio( + TvSettings.PIP_LOCATION_BOTTOM_LEFT, R.drawable.ic_pip_loc_bottom_left)); + items.add(new PipLocationRadio( + TvSettings.PIP_LOCATION_BOTTOM_RIGHT, R.drawable.ic_pip_loc_bottom_right)); + return items; } - @Override - public void onBindView(View v, int position, Object tag, boolean prevSelected) { - super.onBindView(v, position, tag, prevSelected); - ImageView pipLocationImageView = (ImageView) v.findViewById(R.id.pip_location); - int location = (Integer) tag; - if (location == TvSettings.PIP_LOCATION_TOP_LEFT) { - pipLocationImageView.setImageResource(R.drawable.ic_pip_loc_top_left); - } else if (location == TvSettings.PIP_LOCATION_TOP_RIGHT) { - pipLocationImageView.setImageResource(R.drawable.ic_pip_loc_top_right); - } else if (location == TvSettings.PIP_LOCATION_BOTTOM_LEFT) { - pipLocationImageView.setImageResource(R.drawable.ic_pip_loc_bottom_left); - } else if (location == TvSettings.PIP_LOCATION_BOTTOM_RIGHT) { - pipLocationImageView.setImageResource(R.drawable.ic_pip_loc_bottom_right); - } else { - throw new IllegalArgumentException("Invaild PIP location: " + location); + private class PipLocationRadio extends RadioButtonItem { + int mLocation; + int mDrawable; + + private PipLocationRadio(int location, int drawable) { + super(null); + mLocation = location; + mDrawable = drawable; } - } - @Override - public void onItemSelected(View v, int position, Object tag) { - int pipLocation = (Integer) tag; - mTvActivity.setPipLocation(pipLocation, true); - super.onItemSelected(v, position, tag); + @Override + protected void bind(View view) { + super.bind(view); + RadioButton radioButton = (RadioButton) view.findViewById(R.id.radio_button); + BitmapDrawable drawable = (BitmapDrawable) getResources().getDrawable(mDrawable); + drawable.setGravity(Gravity.CENTER); + drawable.setTargetDensity(Bitmap.DENSITY_NONE); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + radioButton.setCompoundDrawablesRelative(drawable, null, null, null); + } + + @Override + protected void onSelected() { + super.onSelected(); + getTvActivity().setPipLocation(mLocation, true); + } } -} +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/RadioButtonItem.java b/src/com/android/tv/ui/sidepanel/RadioButtonItem.java new file mode 100644 index 00000000..c6d4e262 --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/RadioButtonItem.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 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.view.View; +import android.widget.RadioButton; + +import com.android.tv.R; + +public class RadioButtonItem extends Item { + private final String mTitle; + private boolean mChecked; + private RadioButton mRadioButton; + + public RadioButtonItem(String title) { + mTitle = title; + } + + @Override + protected int getResourceId() { + return R.layout.option_item_radio_button; + } + + @Override + protected void bind(View view) { + mRadioButton = (RadioButton) view.findViewById(R.id.radio_button); + mRadioButton.setText(mTitle); + mRadioButton.setChecked(mChecked); + } + + @Override + protected void unbind() { + mRadioButton = null; + } + + @Override + protected void onSelected() { + setChecked(true); + } + + public void setChecked(boolean checked) { + if (mChecked != checked) { + mChecked = checked; + if (mRadioButton != null) { + mRadioButton.setChecked(mChecked); + } + } + } + + public boolean getChecked() { + return mChecked; + } +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/SideFragment.java b/src/com/android/tv/ui/sidepanel/SideFragment.java new file mode 100644 index 00000000..6967a744 --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/SideFragment.java @@ -0,0 +1,149 @@ +package com.android.tv.ui.sidepanel; + +import android.app.Fragment; +import android.os.Bundle; +import android.support.v17.leanback.widget.VerticalGridView; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.android.tv.R; +import com.android.tv.TvActivity; + +import java.util.List; + +public abstract class SideFragment extends Fragment { + public SideFragment() { } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.option_fragment, container, false); + + TextView textView = (TextView) view.findViewById(R.id.side_panel_title); + textView.setText(getTitle()); + + VerticalGridView listView = (VerticalGridView) view.findViewById(R.id.side_panel_list); + listView.setAdapter(new ItemAdapter(inflater, getItemList())); + listView.requestFocus(); + + // TODO find a better way to do this + if (getFragmentManager().getBackStackEntryCount() != 0) { + view.findViewById(R.id.side_panel_shadow).setVisibility(View.GONE); + } + + return view; + } + + @Override + public void onDetach() { + super.onDetach(); + + // TODO find a better way to do this + if (getFragmentManager().getBackStackEntryCount() == 0) { + TvActivity tvActivity = getTvActivity(); + tvActivity.onSideFragmentCanceled(BaseSideFragment.INITIATOR_UNKNOWN); + tvActivity.hideOverlays(false, false, true); + } + } + + protected TvActivity getTvActivity() { + return (TvActivity) getActivity(); + } + + protected void notifyDataSetChanged() { + VerticalGridView listView = (VerticalGridView) getView().findViewById(R.id.side_panel_list); + listView.getAdapter().notifyDataSetChanged(); + } + + protected abstract String getTitle(); + protected abstract List getItemList(); + + private static class ItemAdapter extends RecyclerView.Adapter { + private final LayoutInflater mLayoutInflater; + private final List mItems; + + private ItemAdapter(LayoutInflater layoutInflater, List items) { + mLayoutInflater = layoutInflater; + mItems = items; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = mLayoutInflater.inflate(viewType, parent, false); + final ViewHolder holder = new ViewHolder(view); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (holder.item instanceof RadioButtonItem) { + clearRadioGroup(holder.item); + } + holder.item.onSelected(); + } + }); + view.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean focusGained) { + if (focusGained) { + holder.item.onFocused(); + } + } + }); + return holder; + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + holder.item = getItem(position); + holder.item.bind(holder.itemView); + } + + @Override + public void onViewRecycled(ViewHolder holder) { + holder.item.unbind(); + holder.item = null; + } + + @Override + public int getItemViewType(int position) { + return getItem(position).getResourceId(); + } + + @Override + public int getItemCount() { + return mItems == null ? 0 : mItems.size(); + } + + private Item getItem(int position) { + return mItems.get(position); + } + + private void clearRadioGroup(Item item) { + int position = mItems.indexOf(item); + for (int i = position - 1; i >= 0; --i) { + if ((item = mItems.get(i)) instanceof RadioButtonItem) { + ((RadioButtonItem) item).setChecked(false); + } else { + break; + } + } + for (int i = position + 1; i < mItems.size(); ++i) { + if ((item = mItems.get(i)) instanceof RadioButtonItem) { + ((RadioButtonItem) item).setChecked(false); + } else { + break; + } + } + } + + private static class ViewHolder extends RecyclerView.ViewHolder { + public Item item; + + private ViewHolder(View view) { + super(view); + } + } + } +} \ No newline at end of file diff --git a/src/com/android/tv/ui/sidepanel/SubMenuItem.java b/src/com/android/tv/ui/sidepanel/SubMenuItem.java new file mode 100644 index 00000000..e76eab2e --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/SubMenuItem.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 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.app.FragmentManager; +import android.app.FragmentTransaction; +import android.view.View; +import android.widget.TextView; + +import com.android.tv.R; + +import java.util.List; + +public class SubMenuItem extends Item { + private final String mTitle; + private final FragmentManager mFragmentManager; + private TextView mTitleView; + + public SubMenuItem(String title, FragmentManager fragmentManager) { + mTitle = title; + mFragmentManager = fragmentManager; + } + + @Override + protected int getResourceId() { + return R.layout.option_item_sub_menu; + } + + @Override + protected void bind(View view) { + mTitleView = (TextView) view.findViewById(R.id.title); + mTitleView.setText(mTitle); + } + + @Override + protected void unbind() { + mTitleView = null; + } + + @Override + protected void onSelected() { + mFragmentManager + .beginTransaction() + .add(R.id.right_panel, new SideFragment() { + @Override + protected String getTitle() { + return SubMenuItem.this.getTitle(); + } + + @Override + protected List getItemList() { + return SubMenuItem.this.getItemList(); + } + }) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .addToBackStack(null) + .commit(); + } + + protected String getTitle() { + return mTitle; + } + + protected List getItemList() { + return null; + } +} \ No newline at end of file -- cgit v1.2.3