summaryrefslogtreecommitdiffstats
path: root/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback
diff options
context:
space:
mode:
Diffstat (limited to 'samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback')
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainActivity.java39
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainFragment.java181
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleActivity.java34
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleFragment.java132
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleActivity.java32
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleFragment.java179
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailsDescriptionPresenter.java62
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/ShadowRowPresenterSelector.java44
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleActivity.java35
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleFragment.java67
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleActivity.java30
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleFragment.java72
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MediaPlayerGlue.java446
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicConsumptionExampleFragment.java155
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicExampleActivity.java30
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/SongListRow.java20
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/TrackListHeader.java50
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoConsumptionExampleFragment.java117
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoExampleActivity.java39
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoMediaPlayerGlue.java57
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoSurfaceFragment.java39
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleActivity.java31
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleFragment.java107
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample1stStepFragment.java70
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample2ndStepFragment.java101
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample3rdStepFragment.java98
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample4thStepFragment.java69
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleActivity.java47
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleBaseStepFragment.java47
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/CharacterCardView.java69
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/TextCardView.java56
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/AbstractCardPresenter.java79
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CardPresenterSelector.java92
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CharacterCardPresenter.java40
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/IconCardPresenter.java51
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/ImageCardViewPresenter.java60
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SideInfoCardPresenter.java74
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SingleLineCardPresenter.java38
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/TextCardPresenter.java41
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Card.java129
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/CardRow.java44
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/DetailedCard.java71
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Movie.java50
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Song.java116
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/SongList.java31
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/CardListRow.java45
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Constants.java17
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/PicassoBackgroundManagerTarget.java61
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/ResourceCache.java36
-rw-r--r--samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Utils.java58
50 files changed, 3688 insertions, 0 deletions
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainActivity.java
new file mode 100644
index 000000000..e84c8cc8c
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/*
+ * MainActivity class that loads MainFragment
+ */
+public class MainActivity extends Activity {
+
+ /**
+ * Called when the activity is first created.
+ */
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ if (savedInstanceState == null) {
+ Fragment fragment = new MainFragment();
+ getFragmentManager().beginTransaction().replace(R.id.fragmentContainer, fragment)
+ .commit();
+ }
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainFragment.java
new file mode 100644
index 000000000..ab22928d8
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/MainFragment.java
@@ -0,0 +1,181 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.app.BrowseFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.app.cards.CardExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.details.DetailViewExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.dialog.DialogExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.grid.GridExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.media.MusicExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.media.VideoExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.settings.SettingsExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.wizard.WizardExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.cards.presenters.CardPresenterSelector;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.supportleanbackshowcase.models.CardRow;
+import android.support.v17.leanback.supportleanbackshowcase.models.Movie;
+import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ImageCardView;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v4.app.ActivityOptionsCompat;
+
+import com.google.gson.Gson;
+
+
+public class MainFragment extends BrowseFragment {
+
+ private ArrayObjectAdapter mRowsAdapter;
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ setupUIElements();
+ setupRowAdapter();
+ setupEventListeners();
+ }
+
+ private void setupRowAdapter() {
+ mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
+ createRows();
+ setAdapter(mRowsAdapter);
+ }
+
+ private void createRows() {
+ String json = Utils
+ .inputStreamToString(getResources().openRawResource(R.raw.launcher_cards));
+ CardRow[] rows = new Gson().fromJson(json, CardRow[].class);
+ for (CardRow row : rows) {
+ mRowsAdapter.add(createCardRow(row));
+ }
+ }
+
+ private ListRow createCardRow(CardRow cardRow) {
+ PresenterSelector presenterSelector = new CardPresenterSelector(getActivity());
+ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(presenterSelector);
+ for (Card card : cardRow.getCards()) {
+ listRowAdapter.add(card);
+ }
+ return new ListRow(listRowAdapter);
+ }
+
+ private void setupUIElements() {
+ setTitle(getString(R.string.browse_title));
+ setBadgeDrawable(getResources().getDrawable(R.drawable.title_android_tv, null));
+ setHeadersState(HEADERS_DISABLED);
+ setHeadersTransitionOnBackEnabled(false);
+ setBrandColor(getResources().getColor(R.color.fastlane_background));
+ }
+
+ private void setupEventListeners() {
+ setOnItemViewClickedListener(new ItemViewClickedListener());
+ setOnItemViewSelectedListener(new ItemViewSelectedListener());
+ }
+
+ private final class ItemViewClickedListener implements OnItemViewClickedListener {
+
+ @Override
+ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Intent intent = null;
+ Card card = (Card) item;
+ int id = card.getId();
+ switch (id) {
+ case 0: {
+ intent = new Intent(getActivity().getBaseContext(),
+ CardExampleActivity.class);
+ break;
+ }
+ case 2: {
+ intent = new Intent(getActivity().getBaseContext(),
+ GridExampleActivity.class);
+ break;
+ }
+ case 3: {
+ intent = new Intent(getActivity().getBaseContext(),
+ DetailViewExampleActivity.class);
+ break;
+ }
+ case 4: {
+ intent = new Intent(getActivity().getBaseContext(),
+ VideoExampleActivity.class);
+ break;
+ }
+ case 5: {
+ intent = new Intent(getActivity().getBaseContext(),
+ MusicExampleActivity.class);
+ break;
+ }
+ case 6: {
+ // Let's create a new Wizard for a given Movie. The movie can come from any sort
+ // of data source. To simplify this example we decode it from a JSON source
+ // which might be loaded from a server in a real world example.
+ intent = new Intent(getActivity().getBaseContext(),
+ WizardExampleActivity.class);
+
+ // Prepare extras which contains the Movie and will be passed to the Activity
+ // which is started through the Intent/.
+ Bundle extras = new Bundle();
+ String json = Utils.inputStreamToString(
+ getResources().openRawResource(R.raw.wizard_example));
+ Movie movie = new Gson().fromJson(json, Movie.class);
+ extras.putSerializable("movie", movie);
+ intent.putExtras(extras);
+
+ // Finally, start the wizard Activity.
+ break;
+ }
+ case 7: {
+ intent = new Intent(getActivity().getBaseContext(),
+ SettingsExampleActivity.class);
+ startActivity(intent);
+ return;
+ }
+ case 8: {
+ intent = new Intent(getActivity().getBaseContext(),
+ DialogExampleActivity.class);
+ break;
+ }
+ default:
+ break;
+ }
+ if (intent != null) {
+ Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity())
+ .toBundle();
+ startActivity(intent, bundle);
+ }
+ }
+ }
+
+ private final class ItemViewSelectedListener implements OnItemViewSelectedListener {
+
+ @Override
+ public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ }
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleActivity.java
new file mode 100644
index 000000000..7b8225fe7
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.cards;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.app.dialog.DialogExampleFragment;
+
+/**
+ * TODO: Javadoc
+ */
+public class CardExampleActivity extends Activity {
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_cards_example);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleFragment.java
new file mode 100644
index 000000000..4b2a44557
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/cards/CardExampleFragment.java
@@ -0,0 +1,132 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.cards;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.app.BrowseFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.app.details.DetailViewExampleActivity;
+import android.support.v17.leanback.supportleanbackshowcase.app.details.DetailViewExampleFragment;
+import android.support.v17.leanback.supportleanbackshowcase.app.details.ShadowRowPresenterSelector;
+import android.support.v17.leanback.supportleanbackshowcase.cards.presenters.CardPresenterSelector;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.supportleanbackshowcase.models.CardRow;
+import android.support.v17.leanback.supportleanbackshowcase.utils.CardListRow;
+import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ImageCardView;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.SearchOrbView;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.google.gson.Gson;
+
+/**
+ * This fragment will be shown when the "Card Examples" card is selected at the home menu. It will
+ * display multiple card types.
+ */
+public class CardExampleFragment extends BrowseFragment {
+
+ private ArrayObjectAdapter mRowsAdapter;
+
+ @Override public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ setupUi();
+ setupRowAdapter();
+ }
+
+ private void setupUi() {
+ setHeadersState(HEADERS_ENABLED);
+ setHeadersTransitionOnBackEnabled(true);
+ setSearchAffordanceColors(
+ new SearchOrbView.Colors(getResources().getColor(R.color.search_color),
+ getResources().getColor(R.color.search_bright_color),
+ getResources().getColor(R.color.search_icon_color)));
+ setBrandColor(getResources().getColor(R.color.fastlane_background));
+ setTitle(getString(R.string.card_examples_title));
+ setOnSearchClickedListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Toast.makeText(getActivity(), getString(R.string.implement_search),
+ Toast.LENGTH_LONG).show();
+ }
+ });
+ setOnItemViewClickedListener(new OnItemViewClickedListener() {
+
+ @Override
+ public void onItemClicked(Presenter.ViewHolder viewHolder, Object item, RowPresenter.ViewHolder viewHolder1, Row row) {
+ if (!(item instanceof Card)) return;
+ if (!(viewHolder.view instanceof ImageCardView)) return;
+
+ ImageView imageView = ((ImageCardView) viewHolder.view).getMainImageView();
+ Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
+ imageView, DetailViewExampleFragment.TRANSITION_NAME).toBundle();
+ Intent intent = new Intent(getActivity().getBaseContext(),
+ DetailViewExampleActivity.class);
+ Card card = (Card) item;
+ int imageResId = card.getLocalImageResourceId(getContext());
+ intent.putExtra(DetailViewExampleFragment.EXTRA_CARD, imageResId);
+ startActivity(intent, bundle);
+ }
+
+ });
+
+ prepareEntranceTransition();
+ }
+
+ private void setupRowAdapter() {
+ mRowsAdapter = new ArrayObjectAdapter(new ShadowRowPresenterSelector());
+ setAdapter(mRowsAdapter);
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ createRows();
+ startEntranceTransition();
+ }
+ }, 500);
+ }
+
+ private void createRows() {
+ String json = Utils
+ .inputStreamToString(getResources().openRawResource(R.raw.cards_example));
+ CardRow[] rows = new Gson().fromJson(json, CardRow[].class);
+ for (CardRow row : rows) {
+ mRowsAdapter.add(createCardRow(row));
+ }
+ }
+
+ private ListRow createCardRow(final CardRow cardRow) {
+ // Build main row using the ImageCardViewPresenter.
+ PresenterSelector presenterSelector = new CardPresenterSelector(getActivity());
+ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(presenterSelector);
+ for (Card card : cardRow.getCards()) {
+ listRowAdapter.add(card);
+ }
+ HeaderItem header = new HeaderItem(cardRow.getTitle());
+ return new CardListRow(header, listRowAdapter, cardRow);
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleActivity.java
new file mode 100644
index 000000000..6b9c1434f
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.details;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.app.DetailsFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/**
+ * Contains a {@link DetailsFragment} in order to display more details for a given card.
+ */
+public class DetailViewExampleActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_detail_example);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleFragment.java
new file mode 100644
index 000000000..eed800ffd
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailViewExampleFragment.java
@@ -0,0 +1,179 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.details;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.app.DetailsFragment;
+import android.support.v17.leanback.supportleanbackshowcase.models.DetailedCard;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.utils.CardListRow;
+import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
+import android.support.v17.leanback.supportleanbackshowcase.cards.presenters.CardPresenterSelector;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.DetailsOverviewRow;
+import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
+import android.support.v17.leanback.widget.FullWidthDetailsOverviewSharedElementHelper;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import com.google.gson.Gson;
+
+/**
+ * Displays a card with more details using a {@link DetailsFragment}.
+ */
+public class DetailViewExampleFragment extends DetailsFragment implements OnItemViewClickedListener,
+ OnItemViewSelectedListener {
+
+ public static final String TRANSITION_NAME = "t_for_transition";
+ public static final String EXTRA_CARD = "card";
+
+ private ArrayObjectAdapter mRowsAdapter;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setupUi();
+ setupEventListeners();
+ }
+
+ private void setupUi() {
+ // Load the card we want to display from a JSON resource. This JSON data could come from
+ // anywhere in a real world app, e.g. a server.
+ String json = Utils
+ .inputStreamToString(getResources().openRawResource(R.raw.detail_example));
+ DetailedCard data = new Gson().fromJson(json, DetailedCard.class);
+
+ // Setup fragment
+ setTitle(getString(R.string.detail_view_title));
+
+ FullWidthDetailsOverviewRowPresenter rowPresenter = new FullWidthDetailsOverviewRowPresenter(
+ new DetailsDescriptionPresenter(getActivity())) {
+
+ @Override
+ protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
+ // Customize Actionbar and Content by using custom colors.
+ RowPresenter.ViewHolder viewHolder = super.createRowViewHolder(parent);
+
+ View actionsView = viewHolder.view.
+ findViewById(R.id.details_overview_actions_background);
+ actionsView.setBackgroundColor(getActivity().getResources().
+ getColor(R.color.detail_view_actionbar_background, null));
+
+ View detailsView = viewHolder.view.findViewById(R.id.details_frame);
+ detailsView.setBackgroundColor(
+ getResources().getColor(R.color.detail_view_background, null));
+ return viewHolder;
+ }
+ };
+
+ FullWidthDetailsOverviewSharedElementHelper mHelper = new FullWidthDetailsOverviewSharedElementHelper();
+ mHelper.setSharedElementEnterTransition(getActivity(), TRANSITION_NAME);
+ rowPresenter.setListener(mHelper);
+ rowPresenter.setParticipatingEntranceTransition(false);
+ prepareEntranceTransition();
+
+ ListRowPresenter shadowDisabledRowPresenter = new ListRowPresenter();
+ shadowDisabledRowPresenter.setShadowEnabled(false);
+
+ // Setup PresenterSelector to distinguish between the different rows.
+ ClassPresenterSelector rowPresenterSelector = new ClassPresenterSelector();
+ rowPresenterSelector.addClassPresenter(DetailsOverviewRow.class, rowPresenter);
+ rowPresenterSelector.addClassPresenter(CardListRow.class, shadowDisabledRowPresenter);
+ rowPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
+ mRowsAdapter = new ArrayObjectAdapter(rowPresenterSelector);
+
+ // Setup action and detail row.
+ DetailsOverviewRow detailsOverview = new DetailsOverviewRow(data);
+ int imageResId = data.getLocalImageResourceId(getActivity());
+
+ Bundle extras = getActivity().getIntent().getExtras();
+ if (extras != null && extras.containsKey(EXTRA_CARD)) {
+ imageResId = extras.getInt(EXTRA_CARD, imageResId);
+ }
+ detailsOverview.setImageDrawable(getResources().getDrawable(imageResId, null));
+ ArrayObjectAdapter actionAdapter = new ArrayObjectAdapter();
+ actionAdapter.add(new Action(1, getString(R.string.action_buy) + data.getPrice()));
+ actionAdapter.add(new Action(2, getString(R.string.action_wishlist)));
+ actionAdapter.add(new Action(3, getString(R.string.action_related)));
+ detailsOverview.setActionsAdapter(actionAdapter);
+ mRowsAdapter.add(detailsOverview);
+
+ // Setup related row.
+ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(
+ new CardPresenterSelector(getActivity()));
+ for (Card characterCard : data.getCharacters()) listRowAdapter.add(characterCard);
+ HeaderItem header = new HeaderItem(0, getString(R.string.header_related));
+ mRowsAdapter.add(new CardListRow(header, listRowAdapter, null));
+
+ // Setup recommended row.
+ listRowAdapter = new ArrayObjectAdapter(new CardPresenterSelector(getActivity()));
+ for (Card card : data.getRecommended()) listRowAdapter.add(card);
+ header = new HeaderItem(1, getString(R.string.header_recommended));
+ mRowsAdapter.add(new ListRow(header, listRowAdapter));
+
+ setAdapter(mRowsAdapter);
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ startEntranceTransition();
+ }
+ }, 500);
+ }
+
+ private void setupEventListeners() {
+ setOnItemViewSelectedListener(this);
+ setOnItemViewClickedListener(this);
+ }
+
+ @Override
+ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ if (!(item instanceof Action)) return;
+ Action action = (Action) item;
+ if (action.getId() == 3) {
+ setSelectedPosition(1);
+ } else {
+ Toast.makeText(getActivity(), getString(R.string.action_cicked), Toast.LENGTH_LONG)
+ .show();
+ }
+ }
+
+ @Override
+ public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ if (mRowsAdapter.indexOf(row) > 0) {
+ int backgroundColor = getResources().getColor(R.color.detail_view_related_background,
+ null);
+ getView().setBackgroundColor(backgroundColor);
+ } else {
+ getView().setBackground(null);
+ }
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailsDescriptionPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailsDescriptionPresenter.java
new file mode 100644
index 000000000..b8488a11e
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/DetailsDescriptionPresenter.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.details;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.models.DetailedCard;
+import android.support.v17.leanback.supportleanbackshowcase.utils.ResourceCache;
+import android.support.v17.leanback.widget.Presenter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * This presenter is used to render a {@link DetailedCard} in the {@link
+ * DetailViewExampleFragment}.
+ */
+public class DetailsDescriptionPresenter extends Presenter {
+
+ private ResourceCache mResourceCache = new ResourceCache();
+ private Context mContext;
+
+ public DetailsDescriptionPresenter(Context context) {
+ mContext = context;
+ }
+
+ @Override public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.detail_view_content, null);
+ return new ViewHolder(view);
+ }
+
+ @Override public void onBindViewHolder(ViewHolder viewHolder, Object item) {
+ TextView primaryText = mResourceCache.getViewById(viewHolder.view, R.id.primary_text);
+ TextView sndText1 = mResourceCache.getViewById(viewHolder.view, R.id.secondary_text_first);
+ TextView sndText2 = mResourceCache.getViewById(viewHolder.view, R.id.secondary_text_second);
+ TextView extraText = mResourceCache.getViewById(viewHolder.view, R.id.extra_text);
+
+ DetailedCard card = (DetailedCard) item;
+ primaryText.setText(card.getTitle());
+ sndText1.setText(card.getDescription());
+ sndText2.setText(card.getYear() + "");
+ extraText.setText(card.getText());
+ }
+
+ @Override public void onUnbindViewHolder(ViewHolder viewHolder) {
+ // Nothing to do here.
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/ShadowRowPresenterSelector.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/ShadowRowPresenterSelector.java
new file mode 100644
index 000000000..987365a87
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/details/ShadowRowPresenterSelector.java
@@ -0,0 +1,44 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.details;
+
+import android.support.v17.leanback.supportleanbackshowcase.models.CardRow;
+import android.support.v17.leanback.supportleanbackshowcase.utils.CardListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+
+/**
+ * This {@link PresenterSelector} will return a {@link ListRowPresenter} which has shadow support
+ * enabled or not depending on {@link CardRow#useShadow()} for a given row.
+ */
+public class ShadowRowPresenterSelector extends PresenterSelector {
+
+ private ListRowPresenter mShadowEnabledRowPresenter = new ListRowPresenter();
+ private ListRowPresenter mShadowDisabledRowPresenter = new ListRowPresenter();
+
+ public ShadowRowPresenterSelector() {
+ mShadowDisabledRowPresenter.setShadowEnabled(false);
+ }
+
+ @Override public Presenter getPresenter(Object item) {
+ if (!(item instanceof CardListRow)) return mShadowDisabledRowPresenter;
+ CardListRow listRow = (CardListRow) item;
+ CardRow row = listRow.getCardRow();
+ if (row.useShadow()) return mShadowEnabledRowPresenter;
+ return mShadowDisabledRowPresenter;
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleActivity.java
new file mode 100644
index 000000000..55f75759a
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.dialog;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+
+/**
+ * TODO: Javadoc
+ */
+public class DialogExampleActivity extends Activity {
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#21272A")));
+
+ GuidedStepFragment fragment = new DialogExampleFragment();
+ GuidedStepFragment.addAsRoot(this, fragment, android.R.id.content);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleFragment.java
new file mode 100644
index 000000000..80b22a931
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/dialog/DialogExampleFragment.java
@@ -0,0 +1,67 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.dialog;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.widget.Toast;
+
+import java.util.List;
+
+/**
+ * TODO: Javadoc
+ */
+public class DialogExampleFragment extends GuidedStepFragment {
+
+ private static final int ACTION_ID_POSITIVE = 1;
+ private static final int ACTION_ID_NEGATIVE = ACTION_ID_POSITIVE + 1;
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ Guidance guidance = new Guidance(getString(R.string.dialog_example_title),
+ getString(R.string.dialog_example_description),
+ "", null);
+ return guidance;
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ GuidedAction action = new GuidedAction.Builder()
+ .id(ACTION_ID_POSITIVE)
+ .title(getString(R.string.dialog_example_button_positive)).build();
+ actions.add(action);
+ action = new GuidedAction.Builder()
+ .id(ACTION_ID_NEGATIVE)
+ .title(getString(R.string.dialog_example_button_negative)).build();
+ actions.add(action);
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (ACTION_ID_POSITIVE == action.getId()) {
+ Toast.makeText(getActivity(), R.string.dialog_example_button_toast_positive_clicked,
+ Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getActivity(), R.string.dialog_example_button_toast_negative_clicked,
+ Toast.LENGTH_SHORT).show();
+ }
+ getActivity().finish();
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleActivity.java
new file mode 100644
index 000000000..e2d0887af
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.grid;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/**
+ * TODO: Javadoc
+ */
+public class GridExampleActivity extends Activity {
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_grid_example);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleFragment.java
new file mode 100644
index 000000000..6640b5180
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/grid/GridExampleFragment.java
@@ -0,0 +1,72 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.grid;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.app.VerticalGridFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
+import android.support.v17.leanback.supportleanbackshowcase.models.CardRow;
+import android.support.v17.leanback.supportleanbackshowcase.cards.presenters.CardPresenterSelector;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.FocusHighlight;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.VerticalGridPresenter;
+
+import com.google.gson.Gson;
+
+/**
+ * An example how to use leanback's {@link VerticalGridFragment}.
+ */
+public class GridExampleFragment extends VerticalGridFragment {
+
+ private static final int COLUMNS = 4;
+ private static final int ZOOM_FACTOR = FocusHighlight.ZOOM_FACTOR_MEDIUM;
+
+ private ArrayObjectAdapter mAdapter;
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setTitle(getString(R.string.grid_example_title));
+ setupRowAdapter();
+ }
+
+ private void setupRowAdapter() {
+ VerticalGridPresenter gridPresenter = new VerticalGridPresenter(ZOOM_FACTOR);
+ gridPresenter.setNumberOfColumns(COLUMNS);
+ setGridPresenter(gridPresenter);
+
+ PresenterSelector cardPresenterSelector = new CardPresenterSelector(getActivity());
+ mAdapter = new ArrayObjectAdapter(cardPresenterSelector);
+ setAdapter(mAdapter);
+
+ prepareEntranceTransition();
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ createRows();
+ startEntranceTransition();
+ }
+ }, 1000);
+ }
+
+ private void createRows() {
+ String json = Utils.inputStreamToString(getResources()
+ .openRawResource(R.raw.grid_example));
+ CardRow row = new Gson().fromJson(json, CardRow.class);
+ mAdapter.addAll(0, row.getCards());
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MediaPlayerGlue.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MediaPlayerGlue.java
new file mode 100644
index 000000000..bc757cd19
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MediaPlayerGlue.java
@@ -0,0 +1,446 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Handler;
+import android.support.v17.leanback.app.PlaybackControlGlue;
+import android.support.v17.leanback.app.PlaybackOverlayFragment;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.View;
+
+import java.io.IOException;
+
+/**
+ * This glue extends the {@link PlaybackControlGlue} with a {@link MediaPlayer} synchronization. It
+ * supports 7 actions: <ul> <li>{@link android.support.v17.leanback.widget.PlaybackControlsRow.FastForwardAction}</li>
+ * <li>{@link android.support.v17.leanback.widget.PlaybackControlsRow.RewindAction}</li> <li>{@link
+ * android.support.v17.leanback.widget.PlaybackControlsRow.PlayPauseAction}</li> <li>{@link
+ * android.support.v17.leanback.widget.PlaybackControlsRow.ShuffleAction}</li> <li>{@link
+ * android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction}</li> <li>{@link
+ * android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction}</li> <li>{@link
+ * android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction}</li> </ul>
+ * <p/>
+ */
+public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
+ OnItemViewSelectedListener {
+
+ public static final int FAST_FORWARD_REWIND_STEP = 10 * 1000; // in milliseconds
+ public static final int FAST_FORWARD_REWIND_REPEAT_DELAY = 200; // in milliseconds
+ private static final String TAG = "MediaPlayerGlue";
+ protected final PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
+ protected final PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
+ private final Context mContext;
+ private final MediaPlayer mPlayer = new MediaPlayer();
+ private final PlaybackControlsRow.RepeatAction mRepeatAction;
+ private final PlaybackControlsRow.ShuffleAction mShuffleAction;
+ private PlaybackControlsRow mControlsRow;
+ private Runnable mRunnable;
+ private Handler mHandler = new Handler();
+ private boolean mPaused = false;
+ private boolean mInitialized = false; // true when the MediaPlayer is prepared/initialized
+ private OnMediaFileFinishedPlayingListener mMediaFileFinishedPlayingListener;
+ private Action mSelectedAction; // the action which is currently selected by the user
+ private long mLastKeyDownEvent = 0L; // timestamp when the last DPAD_CENTER KEY_DOWN occurred
+ private MetaData mMetaData;
+ private Uri mMediaSourceUri = null;
+ private String mMediaSourcePath = null;
+
+ public MediaPlayerGlue(Context context, PlaybackOverlayFragment fragment) {
+ super(context, fragment, new int[]{1});
+ mContext = context;
+
+ // Instantiate secondary actions
+ mShuffleAction = new PlaybackControlsRow.ShuffleAction(mContext);
+ mRepeatAction = new PlaybackControlsRow.RepeatAction(mContext);
+ mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(mContext);
+ mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(mContext);
+ mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
+ mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
+
+ // Setup controls and notify UI about change.
+ setFadingEnabled(false);
+ onStateChanged();
+
+ // Register selected listener such that we know what action the user currently has focused.
+ fragment.setOnItemViewSelectedListener(this);
+ }
+
+ /**
+ * Will reset the {@link MediaPlayer} and the glue such that a new file can be played. You are
+ * not required to call this method before playing the first file. However you have to call it
+ * before playing a second one.
+ */
+ public void reset() {
+ mPaused = mInitialized = false;
+ mPlayer.reset();
+ }
+
+ public void setOnMediaFileFinishedPlayingListener(OnMediaFileFinishedPlayingListener listener) {
+ mMediaFileFinishedPlayingListener = listener;
+ }
+
+ /**
+ * Override this method in case you need to add different secondary actions.
+ *
+ * @param secondaryActionsAdapter The adapter you need to add the {@link Action}s to.
+ */
+ protected void addSecondaryActions(ArrayObjectAdapter secondaryActionsAdapter) {
+ secondaryActionsAdapter.add(mShuffleAction);
+ secondaryActionsAdapter.add(mRepeatAction);
+ secondaryActionsAdapter.add(mThumbsDownAction);
+ secondaryActionsAdapter.add(mThumbsUpAction);
+ }
+
+ /**
+ * @see MediaPlayer#setDisplay(SurfaceHolder)
+ */
+ public void setDisplay(SurfaceHolder surfaceHolder) {
+ mPlayer.setDisplay(surfaceHolder);
+ }
+
+ /**
+ * Use this method to setup the {@link PlaybackControlsRowPresenter}. It'll be called
+ * <u>after</u> the {@link PlaybackControlsRowPresenter} has been created and the primary and
+ * secondary actions have been added.
+ *
+ * @param presenter The PlaybackControlsRowPresenter used to display the controls.
+ */
+ public void setupControlsRowPresenter(PlaybackControlsRowPresenter presenter) {
+ // TODO: hahnr@ move into resources
+ presenter.setProgressColor(Color.parseColor("#feab91"));
+ presenter.setBackgroundColor(Color.parseColor("#db2a0f"));
+ }
+
+ @Override public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
+ PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
+ mControlsRow = getControlsRow();
+
+ // Add secondary actions and change the control row color.
+ ArrayObjectAdapter secondaryActions = new ArrayObjectAdapter(
+ new ControlButtonPresenterSelector());
+ mControlsRow.setSecondaryActionsAdapter(secondaryActions);
+ addSecondaryActions(secondaryActions);
+ setupControlsRowPresenter(presenter);
+ return presenter;
+ }
+
+ @Override public void enableProgressUpdating(final boolean enabled) {
+ if (!enabled) {
+ if (mRunnable != null) mHandler.removeCallbacks(mRunnable);
+ return;
+ }
+ mRunnable = new Runnable() {
+ @Override public void run() {
+ updateProgress();
+ Log.d(TAG, "enableProgressUpdating(boolean)");
+ mHandler.postDelayed(this, getUpdatePeriod());
+ }
+ };
+ mHandler.postDelayed(mRunnable, getUpdatePeriod());
+ }
+
+ @Override public void onActionClicked(Action action) {
+ // If either 'Shuffle' or 'Repeat' has been clicked we need to make sure the acitons index
+ // is incremented and the UI updated such that we can display the new state.
+ super.onActionClicked(action);
+ if (action instanceof PlaybackControlsRow.ShuffleAction) {
+ mShuffleAction.nextIndex();
+ } else if (action instanceof PlaybackControlsRow.RepeatAction) {
+ mRepeatAction.nextIndex();
+ } else if (action instanceof PlaybackControlsRow.ThumbsUpAction) {
+ if (mThumbsUpAction.getIndex() == PlaybackControlsRow.ThumbsAction.SOLID) {
+ mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
+ } else {
+ mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.SOLID);
+ mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
+ }
+ } else if (action instanceof PlaybackControlsRow.ThumbsDownAction) {
+ if (mThumbsDownAction.getIndex() == PlaybackControlsRow.ThumbsAction.SOLID) {
+ mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
+ } else {
+ mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.SOLID);
+ mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
+ }
+ }
+ onMetadataChanged();
+ }
+
+ @Override public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // This method is overridden in order to make implement fast forwarding and rewinding when
+ // the user keeps the corresponding action pressed.
+ // We only consume DPAD_CENTER Action_DOWN events on the Fast-Forward and Rewind action and
+ // only if it has not been pressed in the last X milliseconds.
+ boolean consume = mSelectedAction instanceof PlaybackControlsRow.RewindAction;
+ consume = consume || mSelectedAction instanceof PlaybackControlsRow.FastForwardAction;
+ consume = consume && mInitialized;
+ consume = consume && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER;
+ consume = consume && event.getAction() == KeyEvent.ACTION_DOWN;
+ consume = consume && System
+ .currentTimeMillis() - mLastKeyDownEvent > FAST_FORWARD_REWIND_REPEAT_DELAY;
+ if (consume) {
+ mLastKeyDownEvent = System.currentTimeMillis();
+ int newPosition = getCurrentPosition() + FAST_FORWARD_REWIND_STEP;
+ if (mSelectedAction instanceof PlaybackControlsRow.RewindAction) {
+ newPosition = getCurrentPosition() - FAST_FORWARD_REWIND_STEP;
+ }
+ // Make sure the new calculated duration is in the range 0 >= X >= MediaDuration
+ if (newPosition < 0) newPosition = 0;
+ if (newPosition > getMediaDuration()) newPosition = getMediaDuration();
+ seekTo(newPosition);
+ return true;
+ }
+ return super.onKey(v, keyCode, event);
+ }
+
+ @Override public boolean hasValidMedia() {
+ return mMetaData != null;
+ }
+
+ @Override public boolean isMediaPlaying() {
+ return mPlayer.isPlaying();
+ }
+
+ @Override public CharSequence getMediaTitle() {
+ return hasValidMedia() ? mMetaData.getTitle() : "N/a";
+ }
+
+ @Override public CharSequence getMediaSubtitle() {
+ return hasValidMedia() ? mMetaData.getArtist() : "N/a";
+ }
+
+ @Override public int getMediaDuration() {
+ return mInitialized ? mPlayer.getDuration() : 0;
+ }
+
+ @Override public Drawable getMediaArt() {
+ return hasValidMedia() ? mMetaData.getCover() : null;
+ }
+
+ @Override public long getSupportedActions() {
+ return PlaybackControlGlue.ACTION_PLAY_PAUSE | PlaybackControlGlue.ACTION_FAST_FORWARD | PlaybackControlGlue.ACTION_REWIND;
+ }
+
+ @Override public int getCurrentSpeedId() {
+ // 0 = Pause, 1 = Normal Playback Speed
+ return mPlayer.isPlaying() ? 1 : 0;
+ }
+
+ @Override public int getCurrentPosition() {
+ return mInitialized ? mPlayer.getCurrentPosition() : 0;
+ }
+
+ @Override protected void startPlayback(int speed) throws IllegalStateException {
+ if (mPaused) {
+ mPlayer.start();
+ } else if (!isMediaPlaying()) {
+ reset();
+ try {
+ if (mMediaSourceUri != null) mPlayer.setDataSource(getContext(), mMediaSourceUri);
+ else mPlayer.setDataSource(mMediaSourcePath);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override public void onPrepared(MediaPlayer mp) {
+ mInitialized = true;
+ mPaused = false;
+ mPlayer.start();
+ onMetadataChanged();
+ onStateChanged();
+ updateProgress();
+ }
+ });
+ mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ @Override public void onCompletion(MediaPlayer mp) {
+ if (mInitialized && mMediaFileFinishedPlayingListener != null)
+ mMediaFileFinishedPlayingListener.onMediaFileFinishedPlaying(mMetaData);
+ }
+ });
+ mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
+ @Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
+ mControlsRow.setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
+ }
+ });
+ mPlayer.prepareAsync();
+ onStateChanged();
+ }
+ }
+
+ @Override protected void pausePlayback() {
+ if (mPlayer.isPlaying()) {
+ mPlayer.pause();
+ mPaused = true;
+ }
+ }
+
+ @Override protected void skipToNext() {
+ // Not supported.
+ }
+
+ @Override protected void skipToPrevious() {
+ // Not supported.
+ }
+
+ /**
+ * Called whenever the user presses fast-forward/rewind or when the user keeps the corresponding
+ * action pressed.
+ *
+ * @param newPosition The new position of the media track in milliseconds.
+ */
+ protected void seekTo(int newPosition) {
+ mPlayer.seekTo(newPosition);
+ }
+
+ /**
+ * @see MediaPlayer#setDataSource(Context, Uri)
+ */
+ public void setMediaSource(Uri uri) {
+ mMediaSourceUri = uri;
+ }
+
+ /**
+ * @see MediaPlayer#setDataSource(String)
+ */
+ public void setMediaSource(String path) {
+ mMediaSourcePath = path;
+ }
+
+ /**
+ * Call to <code>startPlayback(1)</code>.
+ *
+ * @throws IllegalStateException See {@link MediaPlayer} for further information about it's
+ * different states when setting a data source and preparing it to be played.
+ */
+ public void startPlayback() throws IllegalStateException {
+ startPlayback(1);
+ }
+
+ /**
+ * @return Returns <code>true</code> iff 'Shuffle' is <code>ON</code>.
+ */
+ public boolean useShuffle() {
+ return mShuffleAction.getIndex() == PlaybackControlsRow.ShuffleAction.ON;
+ }
+
+ /**
+ * @return Returns <code>true</code> iff 'Repeat-One' is <code>ON</code>.
+ */
+ public boolean repeatOne() {
+ return mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.ONE;
+ }
+
+ /**
+ * @return Returns <code>true</code> iff 'Repeat-All' is <code>ON</code>.
+ */
+ public boolean repeatAll() {
+ return mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.ALL;
+ }
+
+ public void setMetaData(MetaData metaData) {
+ mMetaData = metaData;
+ onMetadataChanged();
+ }
+
+ /**
+ * This is a listener implementation for the {@link OnItemViewSelectedListener} of the {@link
+ * PlaybackOverlayFragment}. This implementation is required in order to detect KEY_DOWN events
+ * on the {@link android.support.v17.leanback.widget.PlaybackControlsRow.FastForwardAction} and
+ * {@link android.support.v17.leanback.widget.PlaybackControlsRow.RewindAction}. Thus you should
+ * <u>NOT</u> set another {@link OnItemViewSelectedListener} on your {@link
+ * PlaybackOverlayFragment}. Instead, override this method and call its super (this)
+ * implementation.
+ *
+ * @see OnItemViewSelectedListener#onItemSelected(Presenter.ViewHolder, Object,
+ * RowPresenter.ViewHolder, Row)
+ */
+ @Override public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ if (item instanceof Action) {
+ mSelectedAction = (Action) item;
+ } else {
+ mSelectedAction = null;
+ }
+ }
+
+ /**
+ * A listener which will be called whenever a track is finished playing.
+ */
+ public interface OnMediaFileFinishedPlayingListener {
+
+ /**
+ * Called when a track is finished playing.
+ *
+ * @param metaData The track's {@link MetaData} which just finished playing.
+ */
+ void onMediaFileFinishedPlaying(MetaData metaData);
+
+ }
+
+ /**
+ * Holds the meta data such as track title, artist and cover art. It'll be used by the {@link
+ * MediaPlayerGlue}.
+ */
+ public static class MetaData {
+
+ private String mTitle;
+ private String mArtist;
+ private Drawable mCover;
+
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public void setTitle(String title) {
+ this.mTitle = title;
+ }
+
+ public String getArtist() {
+ return mArtist;
+ }
+
+ public void setArtist(String artist) {
+ this.mArtist = artist;
+ }
+
+ public Drawable getCover() {
+ return mCover;
+ }
+
+ public void setCover(Drawable cover) {
+ this.mCover = cover;
+ }
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicConsumptionExampleFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicConsumptionExampleFragment.java
new file mode 100644
index 000000000..fdb8ec41f
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicConsumptionExampleFragment.java
@@ -0,0 +1,155 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v17.leanback.app.PlaybackOverlayFragment;
+import android.support.v17.leanback.supportleanbackshowcase.utils.Constants;
+import android.support.v17.leanback.supportleanbackshowcase.app.media.MediaPlayerGlue;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.app.media.TrackListHeader;
+import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
+import android.support.v17.leanback.supportleanbackshowcase.models.Song;
+import android.support.v17.leanback.supportleanbackshowcase.models.SongList;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+
+import com.google.gson.Gson;
+
+import java.util.List;
+
+/**
+ * This example shows how to play music files and build a simple track list.
+ */
+public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment implements
+ OnItemViewClickedListener, Song.OnSongRowClickListener,
+ MediaPlayerGlue.OnMediaFileFinishedPlayingListener {
+
+ private static final String TAG = "MusicConsumptionExampleFragment";
+ private ArrayObjectAdapter mRowsAdapter;
+ private MediaPlayerGlue mGlue;
+ private int mCurrentSongIndex = 0;
+ private List<Song> mSongList;
+ private boolean mAdapterNotified = false;
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (Constants.LOCAL_LOGD) Log.d(TAG, "onCreate");
+
+ mGlue = new MediaPlayerGlue(getActivity(), this) {
+
+ @Override protected void onRowChanged(PlaybackControlsRow row) {
+ if (mRowsAdapter == null || mAdapterNotified) return;
+ //mAdapterNotified = true;
+ mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
+ }
+ };
+ mGlue.setOnMediaFileFinishedPlayingListener(this);
+
+ String json = Utils.inputStreamToString(
+ getResources().openRawResource(R.raw.music_consumption_example));
+ mSongList = new Gson().fromJson(json, SongList.class).getSongs();
+ Song song = mSongList.get(mCurrentSongIndex);
+ MediaPlayerGlue.MetaData metaData = new MediaPlayerGlue.MetaData();
+ metaData.setArtist(song.getDescription());
+ metaData.setTitle(song.getTitle());
+ metaData.setCover(getResources().getDrawable(song.getImageResource(getActivity()), null));
+ Uri uri = Utils.getResourceUri(getActivity(), song.getFileResource(getActivity()));
+ mGlue.setMetaData(metaData);
+ mGlue.setMediaSource(uri);
+
+ setBackgroundType(PlaybackOverlayFragment.BG_LIGHT);
+ addPlaybackControlsRow();
+ }
+
+ @Override public void onStart() {
+ super.onStart();
+ mGlue.enableProgressUpdating(mGlue.hasValidMedia() && mGlue.isMediaPlaying());
+ }
+
+ @Override public void onStop() {
+ super.onStop();
+ mGlue.enableProgressUpdating(false);
+ mGlue.reset();
+ }
+
+ private void addPlaybackControlsRow() {
+ final PlaybackControlsRowPresenter controlsPresenter = mGlue
+ .createControlsRowAndPresenter();
+ ClassPresenterSelector selector = new ClassPresenterSelector();
+ Song.Presenter songPresenter = new Song.Presenter(getActivity());
+ songPresenter.setOnClickListener(this);
+ selector.addClassPresenter(Song.class, songPresenter);
+ selector.addClassPresenter(TrackListHeader.class,
+ new TrackListHeader.Presenter(getActivity()));
+ selector.addClassPresenter(PlaybackControlsRow.class, controlsPresenter);
+ mRowsAdapter = new ArrayObjectAdapter(selector);
+ mRowsAdapter.add(mGlue.getControlsRow());
+ mRowsAdapter.add(new TrackListHeader());
+ mRowsAdapter.addAll(2, mSongList);
+ setAdapter(mRowsAdapter);
+ setOnItemViewClickedListener(this);
+ }
+
+ @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ if (!(item instanceof Action)) return;
+ mGlue.onActionClicked((Action) item);
+ }
+
+
+ @Override public void onSongRowClicked(Song song) {
+ mCurrentSongIndex = mSongList.indexOf(song);
+ startPlayback();
+ }
+
+
+ @Override public void onMediaFileFinishedPlaying(MediaPlayerGlue.MetaData song) {
+ if (mGlue.repeatOne()) {
+ startPlayback();
+ return;
+ }
+ if (mGlue.useShuffle()) {
+ mCurrentSongIndex = (int) (Math.random() * mSongList.size());
+ } else mCurrentSongIndex++;
+ if (mCurrentSongIndex >= mSongList.size()) {
+ mCurrentSongIndex = 0;
+ if (!mGlue.repeatAll()) return;
+ }
+ startPlayback();
+ }
+
+ private void startPlayback() {
+ Song song = mSongList.get(mCurrentSongIndex);
+ MediaPlayerGlue.MetaData metaData = new MediaPlayerGlue.MetaData();
+ metaData.setArtist(song.getDescription());
+ metaData.setTitle(song.getTitle());
+ metaData.setCover(getResources().getDrawable(song.getImageResource(getActivity()), null));
+
+ Uri uri = Utils.getResourceUri(getActivity(), song.getFileResource(getActivity()));
+ mGlue.setMetaData(metaData);
+ mGlue.setMediaSource(uri);
+ mGlue.startPlayback();
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicExampleActivity.java
new file mode 100644
index 000000000..3107ed615
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/MusicExampleActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/**
+ * TODO: Javadoc
+ */
+public class MusicExampleActivity extends Activity {
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_music_example);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/SongListRow.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/SongListRow.java
new file mode 100644
index 000000000..409613241
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/SongListRow.java
@@ -0,0 +1,20 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.support.v17.leanback.widget.Row;
+
+public class SongListRow extends Row {}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/TrackListHeader.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/TrackListHeader.java
new file mode 100644
index 000000000..ff794a24d
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/TrackListHeader.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class TrackListHeader extends Row {
+
+ public static class Presenter extends RowPresenter {
+
+ private final Context mContext;
+
+ public Presenter(Context context) {
+ mContext = context;
+ setHeaderPresenter(null);
+ }
+
+ @Override public boolean isUsingDefaultSelectEffect() {
+ return false;
+ }
+
+ @Override protected ViewHolder createRowViewHolder(ViewGroup parent) {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.row_track_list_header, parent, false);
+ view.setFocusable(false);
+ view.setFocusableInTouchMode(false);
+ return new ViewHolder(view);
+ }
+ }
+
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoConsumptionExampleFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoConsumptionExampleFragment.java
new file mode 100644
index 000000000..9a40635cf
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoConsumptionExampleFragment.java
@@ -0,0 +1,117 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.v17.leanback.app.PlaybackOverlayFragment;
+import android.support.v17.leanback.supportleanbackshowcase.app.MainFragment;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+
+public class VideoConsumptionExampleFragment extends PlaybackOverlayFragment implements
+ OnItemViewClickedListener, MediaPlayerGlue.OnMediaFileFinishedPlayingListener {
+
+ private static final String URL = "http://techslides.com/demos/sample-videos/small.mp4";
+ private ArrayObjectAdapter mRowsAdapter;
+ private MediaPlayerGlue mGlue;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mGlue = new VideoMediaPlayerGlue(getActivity(), this) {
+
+ @Override
+ protected void onRowChanged(PlaybackControlsRow row) {
+ if (mRowsAdapter == null) return;
+ mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
+ }
+ };
+ mGlue.setOnMediaFileFinishedPlayingListener(this);
+ MediaPlayerGlue.MetaData metaData = new MediaPlayerGlue.MetaData();
+ metaData.setArtist("A Googler");
+ metaData.setTitle("Diving with Sharks");
+ mGlue.setMetaData(metaData);
+ mGlue.setMediaSource(URL);
+
+ Fragment videoSurfaceFragment = getFragmentManager()
+ .findFragmentByTag(VideoExampleActivity.VIDEO_SURFACE_FRAGMENT_TAG);
+ SurfaceView surface = (SurfaceView) videoSurfaceFragment.getView();
+ surface.getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ mGlue.setDisplay(holder);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // Nothing to do
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+ });
+
+ setBackgroundType(PlaybackOverlayFragment.BG_LIGHT);
+ addPlaybackControlsRow();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mGlue.enableProgressUpdating(mGlue.hasValidMedia() && mGlue.isMediaPlaying());
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mGlue.enableProgressUpdating(false);
+ mGlue.reset();
+ }
+
+ private void addPlaybackControlsRow() {
+ final PlaybackControlsRowPresenter controlsPresenter = mGlue
+ .createControlsRowAndPresenter();
+ mRowsAdapter = new ArrayObjectAdapter(controlsPresenter);
+ mRowsAdapter.add(mGlue.getControlsRow());
+ setAdapter(mRowsAdapter);
+ setOnItemViewClickedListener(this);
+ }
+
+ @Override
+ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ if (!(item instanceof Action)) return;
+ mGlue.onActionClicked((Action) item);
+ }
+
+
+ @Override
+ public void onMediaFileFinishedPlaying(MediaPlayerGlue.MetaData metaData) {
+ mGlue.startPlayback();
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoExampleActivity.java
new file mode 100644
index 000000000..63eef8219
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoExampleActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/**
+ * TODO: Javadoc
+ */
+public class VideoExampleActivity extends Activity {
+
+ public static final String VIDEO_SURFACE_FRAGMENT_TAG = "VIDEO_SURFACE";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_video_example);
+
+
+ getFragmentManager().beginTransaction()
+ .replace(R.id.videoFragment, new VideoSurfaceFragment(), VIDEO_SURFACE_FRAGMENT_TAG)
+ .add(R.id.videoFragment, new VideoConsumptionExampleFragment())
+ .commit();
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoMediaPlayerGlue.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoMediaPlayerGlue.java
new file mode 100644
index 000000000..52ab09fb9
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoMediaPlayerGlue.java
@@ -0,0 +1,57 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.v17.leanback.app.PlaybackOverlayFragment;
+import android.support.v17.leanback.supportleanbackshowcase.app.media.MediaPlayerGlue;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+
+public abstract class VideoMediaPlayerGlue extends MediaPlayerGlue {
+
+ private final PlaybackControlsRow.ClosedCaptioningAction mClosedCaptioningAction;
+
+ public VideoMediaPlayerGlue(Context context, PlaybackOverlayFragment fragment) {
+ super(context, fragment);
+
+ // Instantiate secondary actions
+ mClosedCaptioningAction = new PlaybackControlsRow.ClosedCaptioningAction(context);
+ setFadingEnabled(true);
+ }
+
+ @Override protected void addSecondaryActions(ArrayObjectAdapter secondaryActionsAdapter) {
+ secondaryActionsAdapter.add(mClosedCaptioningAction);
+ secondaryActionsAdapter.add(mThumbsDownAction);
+ secondaryActionsAdapter.add(mThumbsUpAction);
+ }
+
+ @Override public void onActionClicked(Action action) {
+ super.onActionClicked(action);
+ if (action == mClosedCaptioningAction) {
+ mClosedCaptioningAction.nextIndex();
+ }
+ }
+
+ public void setupControlsRowPresenter(PlaybackControlsRowPresenter presenter) {
+ // TODO: hahnr@ move into resources
+ presenter.setProgressColor(Color.parseColor("#EEFF41"));
+ presenter.setBackgroundColor(Color.parseColor("#007236"));
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoSurfaceFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoSurfaceFragment.java
new file mode 100644
index 000000000..158a048c4
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/media/VideoSurfaceFragment.java
@@ -0,0 +1,39 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.media;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+
+public class VideoSurfaceFragment extends Fragment {
+
+ private static final String TAG = "VideoSurfaceFragment";
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ }
+
+ @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.video_surface_fragment, null);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleActivity.java
new file mode 100644
index 000000000..01963caf7
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.settings;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/*
+ * TODO: Javadoc
+ */
+public class SettingsExampleActivity extends Activity {
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_settings_example);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleFragment.java
new file mode 100644
index 000000000..b9bb77f6a
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/settings/SettingsExampleFragment.java
@@ -0,0 +1,107 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.settings;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.preference.LeanbackPreferenceFragment;
+import android.support.v17.preference.LeanbackSettingsFragment;
+import android.support.v7.preference.DialogPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.widget.Toast;
+
+import java.util.Arrays;
+import java.util.Stack;
+
+public class SettingsExampleFragment extends LeanbackSettingsFragment implements DialogPreference.TargetFragment {
+
+ private final Stack<Fragment> fragments = new Stack<Fragment>();
+
+ @Override
+ public void onPreferenceStartInitialScreen() {
+ startPreferenceFragment(buildPreferenceFragment(R.xml.prefs, null));
+ }
+
+ @Override
+ public boolean onPreferenceStartFragment(PreferenceFragment preferenceFragment,
+ Preference preference) {
+ return false;
+ }
+
+ @Override
+ public boolean onPreferenceStartScreen(PreferenceFragment preferenceFragment,
+ PreferenceScreen preferenceScreen) {
+ PreferenceFragment frag = buildPreferenceFragment(R.xml.prefs, preferenceScreen.getKey());
+ startPreferenceFragment(frag);
+ return true;
+ }
+
+ @Override
+ public Preference findPreference(CharSequence prefKey) {
+ return ((PreferenceFragment) fragments.peek()).findPreference(prefKey);
+ }
+
+ private PreferenceFragment buildPreferenceFragment(int preferenceResId, String root) {
+ PreferenceFragment fragment = new PrefFragment();
+ Bundle args = new Bundle();
+ args.putInt("preferenceResource", preferenceResId);
+ args.putString("root", root);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ private class PrefFragment extends LeanbackPreferenceFragment {
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String s) {
+ String root = getArguments().getString("root", null);
+ int prefResId = getArguments().getInt("preferenceResource");
+ if (root == null) {
+ addPreferencesFromResource(prefResId);
+ } else {
+ setPreferencesFromResource(prefResId, root);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ final String[] keys = {"prefs_wifi_connect_wps", "prefs_date", "prefs_time",
+ "prefs_date_time_use_timezone", "app_banner_sample_app", "pref_force_stop",
+ "pref_uninstall", "pref_more_info"};
+ if (Arrays.asList(keys).contains(preference.getKey())) {
+ Toast.makeText(getActivity(), "Implement your own action handler.", Toast.LENGTH_SHORT).show();
+ return true;
+ }
+ return super.onPreferenceTreeClick(preference);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ fragments.push(this);
+ super.onAttach(context);
+ }
+
+ @Override
+ public void onDetach() {
+ fragments.pop();
+ super.onDetach();
+ }
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample1stStepFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample1stStepFragment.java
new file mode 100644
index 000000000..b40cc8257
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample1stStepFragment.java
@@ -0,0 +1,70 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.wizard;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidedAction;
+
+import java.util.List;
+
+/**
+ * The first screen of the rental wizard. Gives the user the choice between renting the movie in SD
+ * or HD quality.
+ */
+public class WizardExample1stStepFragment extends WizardExampleBaseStepFragment {
+
+ private static final int ACTION_ID_BUY_HD = 1;
+ private static final int ACTION_ID_BUY_SD = ACTION_ID_BUY_HD + 1;
+
+ @NonNull
+ @Override
+ public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
+ GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(mMovie.getTitle(),
+ getString(R.string.wizard_example_choose_rent_options),
+ mMovie.getBreadcrump(), null);
+ return guidance;
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ GuidedAction action = new GuidedAction.Builder()
+ .id(ACTION_ID_BUY_HD)
+ .title(getString(R.string.wizard_example_rent_hd))
+ .editable(false)
+ .description(mMovie.getPriceHd() + " " +
+ getString(R.string.wizard_example_watch_hd))
+ .build();
+ actions.add(action);
+ action = new GuidedAction.Builder()
+ .id(ACTION_ID_BUY_SD)
+ .title(getString(R.string.wizard_example_rent_sd))
+ .editable(false)
+ .description(mMovie.getPriceSd() + " " +
+ getString(R.string.wizard_example_watch_sd))
+ .build();
+ actions.add(action);
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ boolean rentHd = ACTION_ID_BUY_HD == action.getId();
+ GuidedStepFragment fragment = WizardExample2ndStepFragment.build(rentHd, this);
+ add(getFragmentManager(), fragment);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample2ndStepFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample2ndStepFragment.java
new file mode 100644
index 000000000..c1df8a131
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample2ndStepFragment.java
@@ -0,0 +1,101 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.wizard;
+
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.widget.Toast;
+
+import java.util.List;
+
+/**
+ * Displays the second screen of the rental wizard which requires the user to confirm his purchase.
+ */
+public class WizardExample2ndStepFragment extends WizardExampleBaseStepFragment {
+
+ private static final String ARG_HD = "hd";
+ private static final int ACTION_ID_CONFIRM = 1;
+ private static final int ACTION_ID_PAYMENT_METHOD = ACTION_ID_CONFIRM + 1;
+
+ public static GuidedStepFragment build(boolean hd, WizardExampleBaseStepFragment previousFragment) {
+ GuidedStepFragment fragment = new WizardExample2ndStepFragment();
+ // Reuse the same arguments this fragment was given.
+ Bundle args = previousFragment.getArguments();
+ args.putBoolean(ARG_HD, hd);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
+ GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(mMovie.getTitle(),
+ getString(R.string.wizard_example_rental_period),
+ mMovie.getBreadcrump(), null);
+ return guidance;
+
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ boolean rentHighDefinition = getArguments().getBoolean(ARG_HD);
+
+ GuidedAction action = new GuidedAction.Builder()
+ .id(ACTION_ID_CONFIRM)
+ .title(getString(R.string.wizard_example_rent))
+ .description(rentHighDefinition ? mMovie.getPriceHd() : mMovie.getPriceSd())
+ .editable(false)
+ .build();
+ actions.add(action);
+ action = new GuidedAction.Builder()
+ .id(ACTION_ID_PAYMENT_METHOD)
+ .title(getString(R.string.wizard_example_payment_method))
+ .editTitle("")
+ .description(getString(R.string.wizard_example_input_credit))
+ .editable(true)
+ .build();
+ actions.add(action);
+ }
+
+ @Override
+ public void onGuidedActionEdited(GuidedAction action) {
+ CharSequence editTitle = action.getEditTitle();
+ if (TextUtils.isDigitsOnly(editTitle) && editTitle.length() == 16) {
+ action.setDescription(getString(R.string.wizard_example_visa,
+ editTitle.subSequence(editTitle.length() - 4, editTitle.length())));
+ } else if (editTitle.length() == 0) {
+ action.setDescription(getString(R.string.wizard_example_input_credit));
+ } else {
+ action.setDescription(getString(R.string.wizard_example_input_credit_wrong));
+ }
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (ACTION_ID_CONFIRM == action.getId()) {
+ GuidedStepFragment fragment = new WizardExample3rdStepFragment();
+ fragment.setArguments(getArguments());
+ add(getFragmentManager(), fragment);
+ }
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample3rdStepFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample3rdStepFragment.java
new file mode 100644
index 000000000..37f662f0a
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample3rdStepFragment.java
@@ -0,0 +1,98 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.wizard;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+
+import java.util.List;
+
+/**
+ * This is the third screen of the rental wizard which will display a progressbar while waiting for
+ * the server to process the rental. The server communication is faked for the sake of this example
+ * by waiting four seconds until continuing.
+ */
+public class WizardExample3rdStepFragment extends WizardExampleBaseStepFragment {
+
+ private static final int ACTION_ID_PROCESSING = 1;
+ private final Handler mFakeHttpHandler = new Handler();
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ // Fake Http call by creating some sort of delay.
+ mFakeHttpHandler.postDelayed(fakeHttpRequestRunnable, 4000L);
+ }
+
+ @Override
+ public GuidedActionsStylist onCreateActionsStylist() {
+ GuidedActionsStylist stylist = new GuidedActionsStylist() {
+ @Override
+ public int onProvideItemLayoutId() {
+ return R.layout.wizard_progress_action_item;
+ }
+
+ @Override
+ public int onProvideLayoutId() {
+ return R.layout.wizard_progress_action_container;
+ }
+ };
+ return stylist;
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+
+ // Make sure to cancel the execution of the Runnable in case the fragment is stopped.
+ mFakeHttpHandler.removeCallbacks(fakeHttpRequestRunnable);
+ }
+
+ @NonNull
+ @Override
+ public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
+ GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(mMovie.getTitle(),
+ getString(R.string.wizard_example_just_a_second),
+ mMovie.getBreadcrump(), null);
+ return guidance;
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ GuidedAction action = new GuidedAction.Builder()
+ .id(ACTION_ID_PROCESSING)
+ .title(getString(R.string.wizard_example_processing))
+ .infoOnly(true)
+ .build();
+ actions.add(action);
+ }
+
+ private final Runnable fakeHttpRequestRunnable = new Runnable() {
+ @Override
+ public void run() {
+ GuidedStepFragment fragment = new WizardExample4thStepFragment();
+ fragment.setArguments(getArguments());
+ add(getFragmentManager(), fragment);
+ }
+ };
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample4thStepFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample4thStepFragment.java
new file mode 100644
index 000000000..be5e6459a
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExample4thStepFragment.java
@@ -0,0 +1,69 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.wizard;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.widget.Toast;
+
+import java.util.List;
+
+/**
+ * The last screen of the Wizard gives to options to either watch the rented movie now or later. Due
+ * to keep this example simple and focused on the usage of the GuidedStepFragment, clicking on
+ * either action will end the wizard. You might however start a new Activity playing the movie.
+ */
+public class WizardExample4thStepFragment extends WizardExampleBaseStepFragment {
+
+ private static final int ACTION_ID_WATCH = 1;
+ private static final int ACTION_ID_LATER = ACTION_ID_WATCH + 1;
+
+ @NonNull
+ @Override
+ public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
+ GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(mMovie.getTitle(),
+ getString(R.string.wizard_example_rental_period),
+ mMovie.getBreadcrump(), null);
+ return guidance;
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ GuidedAction action = new GuidedAction.Builder()
+ .id(ACTION_ID_WATCH)
+ .editable(false)
+ .title(getString(R.string.wizard_example_watch_now))
+ .build();
+ actions.add(action);
+ action = new GuidedAction.Builder()
+ .id(ACTION_ID_LATER)
+ .editable(false)
+ .title(getString(R.string.wizard_example_later))
+ .build();
+ actions.add(action);
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (ACTION_ID_WATCH == action.getId()) {
+ Toast.makeText(getActivity(), getString(R.string.wizard_example_watch_now_clicked),
+ Toast.LENGTH_SHORT).show();
+ }
+ getActivity().finish();
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleActivity.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleActivity.java
new file mode 100644
index 000000000..f5d293708
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleActivity.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 android.support.v17.leanback.supportleanbackshowcase.app.wizard;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/**
+ * An Activity displaying a wizard for renting a movie.
+ */
+public class WizardExampleActivity extends Activity {
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawableResource(R.drawable.wizard_background_blackned);
+
+ GuidedStepFragment fragment = new WizardExample1stStepFragment();
+ fragment.setArguments(getIntent().getExtras()); // Delegate Movie to first step.
+ GuidedStepFragment.addAsRoot(this, fragment, android.R.id.content);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (GuidedStepFragment.getCurrentGuidedStepFragment(getFragmentManager())
+ instanceof WizardExample4thStepFragment) {
+ // The user 'bought' the product. When he presses 'Back' the Wizard will be closed and
+ // he will not be send back to 'Processing Payment...'-Screen.
+ finish();
+ } else super.onBackPressed();
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleBaseStepFragment.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleBaseStepFragment.java
new file mode 100644
index 000000000..8fd59814b
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/app/wizard/WizardExampleBaseStepFragment.java
@@ -0,0 +1,47 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.app.wizard;
+
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.supportleanbackshowcase.models.Movie;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+
+/**
+ * A base class which provides all it's implementations with a method #getWizardActivity(). It also
+ * makes sure that the wizard is using the correct theme.
+ */
+public abstract class WizardExampleBaseStepFragment extends GuidedStepFragment {
+
+ protected Movie mMovie;
+
+ @Override
+ public int onProvideTheme() {
+ return R.style.Theme_Example_LeanbackWizard;
+ }
+
+ WizardExampleActivity getWizardActivity() {
+ if (!(getActivity() instanceof WizardExampleActivity)) {
+ throw new IllegalStateException(WizardExampleActivity.class.getName() + " expected.");
+ }
+ return (WizardExampleActivity) getActivity();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mMovie = (Movie) getArguments().getSerializable("movie");
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/CharacterCardView.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/CharacterCardView.java
new file mode 100644
index 000000000..962adb007
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/CharacterCardView.java
@@ -0,0 +1,69 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.BaseCardView;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class CharacterCardView extends BaseCardView {
+
+ public CharacterCardView(Context context) {
+ super(context, null, R.style.CharacterCardStyle);
+ LayoutInflater.from(getContext()).inflate(R.layout.character_card, this);
+ setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ ImageView mainImage = (ImageView) findViewById(R.id.main_image);
+ View container = findViewById(R.id.container);
+ if (hasFocus) {
+ container.setBackgroundResource(R.drawable.character_focused);
+ mainImage.setBackgroundResource(R.drawable.character_focused);
+ } else {
+ container.setBackgroundResource(R.drawable.character_not_focused_padding);
+ mainImage.setBackgroundResource(R.drawable.character_not_focused);
+ }
+ }
+ });
+ setFocusable(true);
+ }
+
+ public void updateUi(Card card) {
+ TextView primaryText = (TextView) findViewById(R.id.primary_text);
+ final ImageView imageView = (ImageView) findViewById(R.id.main_image);
+
+ primaryText.setText(card.getTitle());
+ if (card.getLocalImageResourceName() != null) {
+ int resourceId = card.getLocalImageResourceId(getContext());
+ Bitmap bitmap = BitmapFactory
+ .decodeResource(getContext().getResources(), resourceId);
+ RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(getContext().getResources(), bitmap);
+ drawable.setAntiAlias(true);
+ drawable.setCornerRadius(Math.max(bitmap.getWidth(), bitmap.getHeight()) / 2.0f);
+ imageView.setImageDrawable(drawable);
+ }
+ }
+
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/TextCardView.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/TextCardView.java
new file mode 100644
index 000000000..830b47441
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/TextCardView.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.BaseCardView;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.view.LayoutInflater;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class TextCardView extends BaseCardView {
+
+ public TextCardView(Context context) {
+ super(context, null, R.style.TextCardStyle);
+ LayoutInflater.from(getContext()).inflate(R.layout.text_icon_card, this);
+ setFocusable(true);
+ }
+
+ public void updateUi(Card card) {
+ TextView extraText = (TextView) findViewById(R.id.extra_text);
+ TextView primaryText = (TextView) findViewById(R.id.primary_text);
+ final ImageView imageView = (ImageView) findViewById(R.id.main_image);
+
+ extraText.setText(card.getExtraText());
+ primaryText.setText(card.getTitle());
+
+ // Create a rounded drawable.
+ int resourceId = card.getLocalImageResourceId(getContext());
+ Bitmap bitmap = BitmapFactory
+ .decodeResource(getContext().getResources(), resourceId);
+ RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(getContext().getResources(), bitmap);
+ drawable.setAntiAlias(true);
+ drawable.setCornerRadius(
+ Math.max(bitmap.getWidth(), bitmap.getHeight()) / 2.0f);
+ imageView.setImageDrawable(drawable);
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/AbstractCardPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/AbstractCardPresenter.java
new file mode 100644
index 000000000..0301cdc1c
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/AbstractCardPresenter.java
@@ -0,0 +1,79 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.BaseCardView;
+import android.support.v17.leanback.widget.Presenter;
+import android.view.ViewGroup;
+
+/**
+ * This abstract, generic class will create and manage the
+ * ViewHolder and will provide typed Presenter callbacks such that you do not have to perform casts
+ * on your own.
+ *
+ * @param <CardViewType> The cards' View Type.
+ */
+public abstract class AbstractCardPresenter<CardViewType extends BaseCardView> extends Presenter {
+
+ private static final String TAG = "AbstractCardPresenter";
+ private final Context mContext;
+
+ /**
+ * @param context The current context.
+ */
+ public AbstractCardPresenter(Context context) {
+ mContext = context;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override public final ViewHolder onCreateViewHolder(ViewGroup parent) {
+ CardViewType cardView = onCreateView();
+ return new ViewHolder(cardView);
+ }
+
+ @Override public final void onBindViewHolder(ViewHolder viewHolder, Object item) {
+ Card card = (Card) item;
+ onBindViewHolder(card, (CardViewType) viewHolder.view);
+ }
+
+ @Override public final void onUnbindViewHolder(ViewHolder viewHolder) {
+ onUnbindViewHolder((CardViewType) viewHolder.view);
+ }
+
+ public void onUnbindViewHolder(CardViewType cardView) {
+ // Nothing to clean up. Override if necessary.
+ }
+
+ /**
+ * Invoked when a new view is created.
+ *
+ * @return Returns the newly created view.
+ */
+ protected abstract CardViewType onCreateView();
+
+ /**
+ * Implement this method to update your card's view with the data bound to it.
+ *
+ * @param card The model containing the data for the card.
+ * @param cardView The view the card is bound to.
+ * @see Presenter#onBindViewHolder(Presenter.ViewHolder, Object)
+ */
+ public abstract void onBindViewHolder(Card card, CardViewType cardView);
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CardPresenterSelector.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CardPresenterSelector.java
new file mode 100644
index 000000000..1228b14a9
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CardPresenterSelector.java
@@ -0,0 +1,92 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+
+import java.util.HashMap;
+
+/**
+ * This PresenterSelector will decide what Presenter to use depending on a given card's type.
+ */
+public class CardPresenterSelector extends PresenterSelector {
+
+ private final Context mContext;
+ private final HashMap<Card.Type, Presenter> presenters = new HashMap<Card.Type, Presenter>();
+
+ public CardPresenterSelector(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public Presenter getPresenter(Object item) {
+ if (!(item instanceof Card)) throw new RuntimeException(
+ String.format("The PresenterSelector only supports data items of type '%s'",
+ Card.class.getName()));
+ Card card = (Card) item;
+ Presenter presenter = presenters.get(card.getType());
+ if (presenter == null) {
+ switch (card.getType()) {
+ case SINGLE_LINE:
+ presenter = new SingleLineCardPresenter(mContext);
+ break;
+ case MOVIE:
+ case MOVIE_BASE:
+ case MOVIE_COMPLETE:
+ case SQUARE_BIG:
+ case GRID_SQUARE:
+ case GAME: {
+ int style = R.style.MovieCardSimpleStyle;
+ if (card.getType() == Card.Type.MOVIE_BASE) {
+ style = R.style.MovieCardBasicStyle;
+ } else if (card.getType() == Card.Type.MOVIE_COMPLETE) {
+ style = R.style.MovieCardCompleteStyle;
+ } else if (card.getType() == Card.Type.SQUARE_BIG) {
+ style = R.style.SquareBigCard;
+ } else if (card.getType() == Card.Type.GRID_SQUARE) {
+ style = R.style.GridCardStyle;
+ } else if (card.getType() == Card.Type.GAME) {
+ style = R.style.GameCardStyle;
+ }
+ presenter = new ImageCardViewPresenter(mContext, style);
+ break;
+ }
+ case SIDE_INFO:
+ presenter = new SideInfoCardPresenter(mContext);
+ break;
+ case TEXT:
+ presenter = new TextCardPresenter(mContext);
+ break;
+ case ICON:
+ presenter = new IconCardPresenter(mContext);
+ break;
+ case CHARACTER:
+ presenter = new CharacterCardPresenter(mContext);
+ break;
+ default:
+ presenter = new ImageCardViewPresenter(mContext);
+ break;
+ }
+ }
+ presenters.put(card.getType(), presenter);
+ return presenter;
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CharacterCardPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CharacterCardPresenter.java
new file mode 100644
index 000000000..35a42a969
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/CharacterCardPresenter.java
@@ -0,0 +1,40 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.cards.CharacterCardView;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+
+/**
+ * This Presenter is used to display the characters card row in the DetailView examples.
+ */
+public class CharacterCardPresenter extends AbstractCardPresenter<CharacterCardView> {
+
+ public CharacterCardPresenter(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected CharacterCardView onCreateView() {
+ return new CharacterCardView(getContext());
+ }
+
+ @Override
+ public void onBindViewHolder(Card card, CharacterCardView cardView) {
+ cardView.updateUi(card);
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/IconCardPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/IconCardPresenter.java
new file mode 100644
index 000000000..bf5be70f4
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/IconCardPresenter.java
@@ -0,0 +1,51 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.ImageCardView;
+import android.view.View;
+import android.widget.ImageView;
+
+/**
+ * This Presenter will display cards which consists of a single icon which will be highlighted by a
+ * surrounding circle when the card is focused. AndroidTV uses these cards for entering settings
+ * menu.
+ */
+public class IconCardPresenter extends ImageCardViewPresenter {
+
+ public IconCardPresenter(Context context) {
+ super(context, R.style.IconCardStyle);
+ }
+
+ @Override
+ protected ImageCardView onCreateView() {
+ final ImageCardView imageCardView = super.onCreateView();
+ final ImageView image = imageCardView.getMainImageView();
+ imageCardView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ image.setBackgroundResource(R.drawable.icon_focused);
+ } else {
+ image.setBackground(null);
+ }
+ }
+ });
+ return imageCardView;
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/ImageCardViewPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/ImageCardViewPresenter.java
new file mode 100644
index 000000000..813c1e78d
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/ImageCardViewPresenter.java
@@ -0,0 +1,60 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.ImageCardView;
+import com.squareup.picasso.Picasso;
+
+/**
+ * A very basic {@link ImageCardView} {@link android.support.v17.leanback.widget.Presenter}.You can
+ * pass a custom style for the ImageCardView in the constructor. Use the default constructor to
+ * create a Presenter with a default ImageCardView style.
+ */
+public class ImageCardViewPresenter extends AbstractCardPresenter<ImageCardView> {
+
+ private final int mCardStyleResId;
+
+ public ImageCardViewPresenter(Context context, int cardStyleResId) {
+ super(context);
+ mCardStyleResId = cardStyleResId;
+ }
+
+ public ImageCardViewPresenter(Context context) {
+ super(context);
+ mCardStyleResId = R.style.DefaultCardStyle;
+ }
+
+ @Override
+ protected ImageCardView onCreateView() {
+ return new ImageCardView(getContext(), mCardStyleResId);
+ }
+
+ @Override
+ public void onBindViewHolder(Card card, final ImageCardView cardView) {
+ cardView.setTag(card);
+ cardView.setTitleText(card.getTitle());
+ cardView.setContentText(card.getDescription());
+ if (card.getLocalImageResourceName() != null) {
+ int resourceId = getContext().getResources()
+ .getIdentifier(card.getLocalImageResourceName(),
+ "drawable", getContext().getPackageName());
+ Picasso.with(getContext()).load(resourceId).into(cardView.getMainImageView());
+ }
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SideInfoCardPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SideInfoCardPresenter.java
new file mode 100644
index 000000000..b9f44fc43
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SideInfoCardPresenter.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.BaseCardView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.squareup.picasso.Picasso;
+
+/**
+ * This Presenter will display a card consisting of an image on the left side of the card followed
+ * by text on the right side. The image and text have equal width. The text will work like a info
+ * box, thus it will be hidden if the parent row is inactive. This behavior is unique to this card
+ * and requires a special focus handler.
+ */
+public class SideInfoCardPresenter extends AbstractCardPresenter<BaseCardView> {
+
+ public SideInfoCardPresenter(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected BaseCardView onCreateView() {
+ final BaseCardView cardView = new BaseCardView(getContext(), null,
+ R.style.SideInfoCardStyle);
+ cardView.setFocusable(true);
+ cardView.addView(LayoutInflater.from(getContext()).inflate(R.layout.side_info_card, null));
+ return cardView;
+ }
+
+ @Override
+ public void onBindViewHolder(Card card, BaseCardView cardView) {
+ ImageView imageView = (ImageView) cardView.findViewById(R.id.main_image);
+ if (card.getLocalImageResourceName() != null) {
+ int width = (int) getContext().getResources()
+ .getDimension(R.dimen.sidetext_image_card_width);
+ int height = (int) getContext().getResources()
+ .getDimension(R.dimen.sidetext_image_card_height);
+ int resourceId = getContext().getResources()
+ .getIdentifier(card.getLocalImageResourceName(),
+ "drawable", getContext().getPackageName());
+ Picasso.with(getContext()).load(resourceId).resize(width, height).centerCrop()
+ .into(imageView);
+ }
+
+ TextView primaryText = (TextView) cardView.findViewById(R.id.primary_text);
+ primaryText.setText(card.getTitle());
+
+ TextView secondaryText = (TextView) cardView.findViewById(R.id.secondary_text);
+ secondaryText.setText(card.getDescription());
+
+ TextView extraText = (TextView) cardView.findViewById(R.id.extra_text);
+ extraText.setText(card.getExtraText());
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SingleLineCardPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SingleLineCardPresenter.java
new file mode 100644
index 000000000..24dedd5c6
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/SingleLineCardPresenter.java
@@ -0,0 +1,38 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+import android.support.v17.leanback.widget.ImageCardView;
+
+/**
+ * This Presenter will display a card which consists of a big image followed by a colored footer.
+ * Not only the colored footer is unique to this card, but also it's footer (info) will be visible
+ * even when its parent row is inactive.
+ */
+public class SingleLineCardPresenter extends ImageCardViewPresenter {
+
+ public SingleLineCardPresenter(Context context) {
+ super(context, R.style.SingleLineCardStyle);
+ }
+
+ @Override public void onBindViewHolder(Card card, ImageCardView cardView) {
+ super.onBindViewHolder(card, cardView);
+ cardView.setInfoAreaBackgroundColor(card.getFooterColor());
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/TextCardPresenter.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/TextCardPresenter.java
new file mode 100644
index 000000000..7e65f0f13
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/cards/presenters/TextCardPresenter.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.cards.presenters;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.cards.TextCardView;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+
+/**
+ * The Presenter displays a card consisting of text as a replacement for a big image. The footer is
+ * also quite unique since it does contain two images rather than one or non.
+ */
+public class TextCardPresenter extends AbstractCardPresenter<TextCardView> {
+
+ public TextCardPresenter(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected TextCardView onCreateView() {
+ return new TextCardView(getContext());
+ }
+
+ @Override
+ public void onBindViewHolder(Card card, TextCardView cardView) {
+ cardView.updateUi(card);
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Card.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Card.java
new file mode 100644
index 000000000..ccaaf72df
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Card.java
@@ -0,0 +1,129 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.models;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.util.Log;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * This is a generic example of a custom data object, containing info we might want to keep with
+ * each card on the home screen
+ */
+public class Card {
+
+ @SerializedName("title") private String mTitle = "";
+ @SerializedName("description") private String mDescription = "";
+ @SerializedName("extraText") private String mExtraText = "";
+ @SerializedName("imageUrl") private String mImageUrl;
+ @SerializedName("footerColor") private String mFooterColor = null;
+ @SerializedName("selectedColor") private String mSelectedColor = null;
+ @SerializedName("localImageResource") private String mLocalImageResource = null;
+ @SerializedName("footerIconLocalImageResource") private String mFooterResource = null;
+ @SerializedName("type") private Card.Type mType;
+ @SerializedName("id") private int mId;
+ @SerializedName("width") private int mWidth;
+ @SerializedName("height") private int mHeight;
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public int getWidth() {
+ return mWidth;
+ }
+
+ public int getHeight() {
+ return mHeight;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public Card.Type getType() {
+ return mType;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public String getExtraText() {
+ return mExtraText;
+ }
+
+ public int getFooterColor() {
+ if (mFooterColor == null) return -1;
+ return Color.parseColor(mFooterColor);
+ }
+
+ public int getSelectedColor() {
+ if (mSelectedColor == null) return -1;
+ return Color.parseColor(mSelectedColor);
+ }
+
+ public String getImageUrl() {
+ return mImageUrl;
+ }
+
+ public URI getImageURI() {
+ if (getImageUrl() == null) return null;
+ try {
+ return new URI(getImageUrl());
+ } catch (URISyntaxException e) {
+ Log.d("URI exception: ", getImageUrl());
+ return null;
+ }
+ }
+
+ public int getLocalImageResourceId(Context context) {
+ return context.getResources().getIdentifier(getLocalImageResourceName(), "drawable",
+ context.getPackageName());
+ }
+
+ public String getLocalImageResourceName() {
+ return mLocalImageResource;
+ }
+
+ public String getFooterLocalImageResourceName() {
+ return mFooterResource;
+ }
+
+ public enum Type {
+
+ MOVIE_COMPLETE,
+ MOVIE,
+ MOVIE_BASE,
+ ICON,
+ SQUARE_BIG,
+ SINGLE_LINE,
+ GAME,
+ SQUARE_SMALL,
+ DEFAULT,
+ SIDE_INFO,
+ SIDE_INFO_TEST_1,
+ TEXT,
+ CHARACTER,
+ GRID_SQUARE
+
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/CardRow.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/CardRow.java
new file mode 100644
index 000000000..932b9b940
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/CardRow.java
@@ -0,0 +1,44 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.models;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+/**
+ * This class represents a row of cards. In a real world application you might want to store more
+ * data than in this example.
+ */
+public class CardRow {
+
+ // Used to determine whether the row shall use shadows when displaying its cards or not.
+ @SerializedName("shadow") private boolean mShadow = true;
+ @SerializedName("title") private String mTitle;
+ @SerializedName("cards") private List<Card> mCards;
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public boolean useShadow() {
+ return mShadow;
+ }
+
+ public List<Card> getCards() {
+ return mCards;
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/DetailedCard.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/DetailedCard.java
new file mode 100644
index 000000000..8727a4053
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/DetailedCard.java
@@ -0,0 +1,71 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.models;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.models.Card;
+
+import com.google.gson.annotations.SerializedName;
+
+public class DetailedCard {
+
+ @SerializedName("title") private String mTitle = "";
+ @SerializedName("description") private String mDescription = "";
+ @SerializedName("text") private String mText = "";
+ @SerializedName("localImageResource") private String mLocalImageResource = null;
+ @SerializedName("price") private String mPrice = null;
+ @SerializedName("characters") private Card[] mCharacters = null;
+ @SerializedName("recommended") private Card[] mRecommended = null;
+ @SerializedName("year") private int mYear = 0;
+
+
+ public String getPrice() {
+ return mPrice;
+ }
+
+ public int getYear() {
+ return mYear;
+ }
+
+ public String getLocalImageResource() {
+ return mLocalImageResource;
+ }
+
+ public String getText() {
+ return mText;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public Card[] getCharacters() {
+ return mCharacters;
+ }
+
+ public Card[] getRecommended() {
+ return mRecommended;
+ }
+
+ public int getLocalImageResourceId(Context context) {
+ return context.getResources()
+ .getIdentifier(getLocalImageResource(), "drawable", context.getPackageName());
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Movie.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Movie.java
new file mode 100644
index 000000000..83912b3a0
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Movie.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.models;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.Serializable;
+
+public class Movie implements Serializable {
+
+ private static final long serialVersionUID = 133742L;
+
+ @SerializedName("title")
+ private String mTitle = "";
+ @SerializedName("price_hd")
+ private String mPriceHd = "n/a";
+ @SerializedName("price_sd")
+ private String mPriceSd = "n/a";
+ @SerializedName("breadcrump")
+ private String mBreadcrump = "";
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public String getBreadcrump() {
+ return mBreadcrump;
+ }
+
+ public String getPriceHd() {
+ return mPriceHd;
+ }
+
+ public String getPriceSd() {
+ return mPriceSd;
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Song.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Song.java
new file mode 100644
index 000000000..89729be80
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/Song.java
@@ -0,0 +1,116 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.models;
+
+import android.content.Context;
+import android.support.v17.leanback.supportleanbackshowcase.R;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.gson.annotations.SerializedName;
+
+public class Song extends Row {
+
+ @SerializedName("title") private String mTitle = "";
+ @SerializedName("description") private String mDescription = "";
+ @SerializedName("text") private String mText = "";
+ @SerializedName("image") private String mImage = null;
+ @SerializedName("file") private String mFile = null;
+ @SerializedName("duration") private String mDuration = null;
+ @SerializedName("number") private int mNumber = 0;
+
+
+ public String getDuration() {
+ return mDuration;
+ }
+
+ public int getNumber() {
+ return mNumber;
+ }
+
+ public String getText() {
+ return mText;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public int getFileResource(Context context) {
+ return context.getResources()
+ .getIdentifier(mFile, "raw", context.getPackageName());
+ }
+
+ public int getImageResource(Context context) {
+ return context.getResources()
+ .getIdentifier(mImage, "drawable", context.getPackageName());
+ }
+
+ public interface OnSongRowClickListener {
+
+ void onSongRowClicked(Song song);
+
+ }
+
+ public static class Presenter extends RowPresenter implements View.OnClickListener {
+
+ private final Context mContext;
+ private OnSongRowClickListener mClickListener;
+
+
+ public Presenter(Context context) {
+ mContext = context;
+ setHeaderPresenter(null);
+ }
+
+ public void setOnClickListener(OnSongRowClickListener listener) {
+ mClickListener = listener;
+ }
+
+ @Override protected ViewHolder createRowViewHolder(ViewGroup parent) {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.row_song, parent, false);
+ view.findViewById(R.id.rowContainer).setOnClickListener(this);
+ return new ViewHolder(view);
+ }
+
+ @Override public boolean isUsingDefaultSelectEffect() {
+ return false;
+ }
+
+ @Override protected void onBindRowViewHolder(ViewHolder vh, Object item) {
+ super.onBindRowViewHolder(vh, item);
+ Song song = (Song) item;
+ ((TextView) vh.view.findViewById(R.id.trackNumber)).setText("" + song.getNumber());
+ ((TextView) vh.view.findViewById(R.id.trackDuration)).setText(song.getDuration());
+ String text = song.getTitle() + " / " + song.getDescription();
+ ((TextView) vh.view.findViewById(R.id.trackName)).setText(text);
+ vh.view.findViewById(R.id.rowContainer).setTag(item);
+ }
+
+ @Override public void onClick(View v) {
+ if (mClickListener == null) return;
+ mClickListener.onSongRowClicked((Song) v.getTag());
+ }
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/SongList.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/SongList.java
new file mode 100644
index 000000000..034ae19b5
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/models/SongList.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.models;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+/**
+ */
+public class SongList {
+
+ @SerializedName("songs") private List<Song> mSongs;
+
+ public List<Song> getSongs() {
+ return mSongs;
+ }
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/CardListRow.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/CardListRow.java
new file mode 100644
index 000000000..19f2437da
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/CardListRow.java
@@ -0,0 +1,45 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.utils;
+
+import android.support.v17.leanback.supportleanbackshowcase.app.details.ShadowRowPresenterSelector;
+import android.support.v17.leanback.supportleanbackshowcase.models.CardRow;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ObjectAdapter;
+
+/**
+ * The {@link CardListRow} allows the {@link ShadowRowPresenterSelector} to access the {@link CardRow}
+ * held by the row and determine whether to use a {@link android.support.v17.leanback.widget.Presenter}
+ * with or without a shadow.
+ */
+public class CardListRow extends ListRow {
+
+ private CardRow mCardRow;
+
+ public CardListRow(HeaderItem header, ObjectAdapter adapter, CardRow cardRow) {
+ super(header, adapter);
+ setCardRow(cardRow);
+ }
+
+ public CardRow getCardRow() {
+ return mCardRow;
+ }
+
+ public void setCardRow(CardRow cardRow) {
+ this.mCardRow = cardRow;
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Constants.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Constants.java
new file mode 100644
index 000000000..1c9dd9cf6
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Constants.java
@@ -0,0 +1,17 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.utils;
+
+public class Constants {
+
+ public static final boolean LOCAL_LOGD = true;
+
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/PicassoBackgroundManagerTarget.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/PicassoBackgroundManagerTarget.java
new file mode 100644
index 000000000..2723d0b07
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/PicassoBackgroundManagerTarget.java
@@ -0,0 +1,61 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.support.v17.leanback.app.BackgroundManager;
+
+import com.squareup.picasso.Picasso;
+import com.squareup.picasso.Target;
+
+/**
+ * Picasso target for updating default_background images
+ */
+public class PicassoBackgroundManagerTarget implements Target {
+
+ private BackgroundManager mBackgroundManager;
+
+ public PicassoBackgroundManagerTarget(BackgroundManager backgroundManager) {
+ this.mBackgroundManager = backgroundManager;
+ }
+
+ @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
+ this.mBackgroundManager.setBitmap(bitmap);
+ }
+
+ @Override public void onBitmapFailed(Drawable drawable) {
+ this.mBackgroundManager.setDrawable(drawable);
+ }
+
+ @Override public void onPrepareLoad(Drawable drawable) {
+ // Do nothing, default_background manager has its own transitions
+ }
+
+ @Override public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PicassoBackgroundManagerTarget that = (PicassoBackgroundManagerTarget) o;
+
+ if (!mBackgroundManager.equals(that.mBackgroundManager)) return false;
+
+ return true;
+ }
+
+ @Override public int hashCode() {
+ return mBackgroundManager.hashCode();
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/ResourceCache.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/ResourceCache.java
new file mode 100644
index 000000000..09a196565
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/ResourceCache.java
@@ -0,0 +1,36 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.utils;
+
+import android.util.SparseArray;
+import android.view.View;
+
+/**
+ * ResourceCache allows retrieving children from a given view and caches the resulting views in
+ * order to prevent future lookups.
+ */
+public class ResourceCache {
+
+ private final SparseArray<View> mCachedViews = new SparseArray<View>();
+
+ public <ViewType extends View> ViewType getViewById(View view, int resId) {
+ View child = mCachedViews.get(resId, null);
+ if (child == null) {
+ child = view.findViewById(resId);
+ mCachedViews.put(resId, child);
+ }
+ return (ViewType) child;
+ }
+}
diff --git a/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Utils.java b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Utils.java
new file mode 100644
index 000000000..4416cbe49
--- /dev/null
+++ b/samples/SupportLeanbackShowcase/app/src/main/java/android/support/v17/leanback/supportleanbackshowcase/utils/Utils.java
@@ -0,0 +1,58 @@
+/*
+ * 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 android.support.v17.leanback.supportleanbackshowcase.utils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A collection of utility methods, all static.
+ */
+public class Utils {
+
+ public static int convertDpToPixel(Context ctx, int dp) {
+ float density = ctx.getResources().getDisplayMetrics().density;
+ return Math.round((float) dp * density);
+ }
+
+ /**
+ * Will read the content from a given {@link InputStream} and return it as a {@link String}.
+ *
+ * @param inputStream The {@link InputStream} which should be read.
+ * @return Returns <code>null</code> if the the {@link InputStream} could not be read. Else
+ * returns the content of the {@link InputStream} as {@link String}.
+ */
+ public static String inputStreamToString(InputStream inputStream) {
+ try {
+ byte[] bytes = new byte[inputStream.available()];
+ inputStream.read(bytes, 0, bytes.length);
+ String json = new String(bytes);
+ return json;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ public static Uri getResourceUri(Context context, int resID) {
+ return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ context.getResources().getResourcePackageName(resID) + '/' +
+ context.getResources().getResourceTypeName(resID) + '/' +
+ context.getResources().getResourceEntryName(resID));
+ }
+}