am 1063d9b4: Add samples for new DetailsFragment

* commit '1063d9b435f91ebc8306c407cfa0a82223beb148':
  Add samples for new DetailsFragment
This commit is contained in:
Dake Gu
2015-05-05 18:33:01 +00:00
committed by Android Git Automerger
10 changed files with 460 additions and 3 deletions

View File

@@ -33,6 +33,10 @@
android:theme="@style/Theme.Example.Leanback.Details"
android:exported="true" />
<activity android:name="SearchDetailsActivity"
android:theme="@style/Theme.Example.Leanback.SearchDetails"
android:exported="true" />
<activity android:name="RowsActivity"
android:theme="@style/Theme.Example.Leanback.Rows"
android:exported="true" />
@@ -56,5 +60,9 @@
android:theme="@style/Theme.Example.Leanback.GuidedStep"
android:exported="true" />
<activity android:name="DetailsPresenterSelectionActivity"
android:theme="@style/Theme.Example.Leanback.GuidedStep"
android:exported="true" />
</application>
</manifest>

View File

@@ -16,7 +16,7 @@
-->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.example.android.leanback.DetailsFragment"
android:name="com.example.android.leanback.NewDetailsFragment"
android:id="@+id/details_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.example.android.leanback.DetailsFragment"
android:id="@+id/details_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

View File

@@ -25,6 +25,8 @@
<string name="search_description">SearchFragment test</string>
<string name="details">Details</string>
<string name="details_description">DetailsFragment test</string>
<string name="search_details">Search Details</string>
<string name="search_details_description">Search style DetailsFragment test</string>
<string name="playback">Playback</string>
<string name="playback_description">PlaybackOverlay test</string>
<string name="hgrid">Horizontal Grid</string>
@@ -35,6 +37,10 @@
<string name="guidedstep_description">GuidedStepFragment test</string>
<string name="browseerror">Browse Error</string>
<string name="browseerror_description">BrowseError test</string>
<string name="detail_presenter_options">Choose Presenter for Details</string>
<string name="detail_presenter_options_description">Choose Presenter for Details</string>
<string name="legacydetails_off">Use New DetailsPresenter</string>
<string name="legacydetails_on">Use Legacy DetailsPresenter</string>
<!-- Strings related to guided sequence activity -->
<string name="guidedstep_first_title">First</string>

View File

@@ -19,6 +19,8 @@
</style>
<style name="Theme.Example.Leanback.Browse" parent="Theme.Leanback.Browse">
</style>
<style name="Theme.Example.Leanback.SearchDetails" parent="Theme.Leanback.Details.NoSharedElementTransition">
</style>
<style name="Theme.Example.Leanback.Details" parent="Theme.Leanback.Details">
</style>
<style name="Theme.Example.Leanback.Rows" parent="Theme.Leanback">

View File

@@ -21,17 +21,28 @@ public class DetailsActivity extends Activity
public static final String EXTRA_ITEM = "item";
public static final String SHARED_ELEMENT_NAME = "hero";
public static boolean USE_LEGACY_PRESENTER = false;
private boolean useLegacyFragment() {
return (USE_LEGACY_PRESENTER && !(this instanceof SearchDetailsActivity));
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.details);
setContentView(useLegacyFragment() ? R.layout.legacy_details : R.layout.details);
if (savedInstanceState == null) {
// Only pass object to fragment when activity is first time created,
// later object is modified and persisted with fragment state.
((DetailsFragment)getFragmentManager().findFragmentById(R.id.details_fragment))
if (useLegacyFragment()) {
((DetailsFragment)getFragmentManager().findFragmentById(R.id.details_fragment))
.setItem((PhotoItem) getIntent().getParcelableExtra(EXTRA_ITEM));
} else {
((NewDetailsFragment)getFragmentManager().findFragmentById(R.id.details_fragment))
.setItem((PhotoItem) getIntent().getParcelableExtra(EXTRA_ITEM));
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.leanback;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v17.leanback.app.GuidedStepFragment;
import android.support.v17.leanback.widget.GuidedAction;
import android.support.v17.leanback.widget.GuidanceStylist;
import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import java.util.List;
import java.util.ArrayList;
/**
* Activity that showcases different aspects of GuidedStepFragments.
*/
public class DetailsPresenterSelectionActivity extends Activity {
private static final int OPTION_CHECK_SET_ID = 10;
private static final long ACTION_ID_SWITCH_LEGACY_ON = 10000;
private static final long ACTION_ID_SWITCH_LEGACY_OFF = 10001;
private static final String[] OPTION_NAMES = { "Use new details presenter", "Use legacy details presenter" };
private static final String[] OPTION_DESCRIPTIONS = { "Use new details presenter",
"Use legacy details presenter"};
private static final long[] OPTION_IDS = {ACTION_ID_SWITCH_LEGACY_OFF, ACTION_ID_SWITCH_LEGACY_ON};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GuidedStepFragment.add(getFragmentManager(), new SetupFragment());
}
private static void addAction(List<GuidedAction> actions, long id, String title, String desc) {
actions.add(new GuidedAction.Builder()
.id(id)
.title(title)
.description(desc)
.build());
}
private static void addCheckedAction(List<GuidedAction> actions, Context context,
long id, String title, String desc, boolean checked) {
actions.add(new GuidedAction.Builder()
.title(title)
.description(desc)
.id(id)
.checkSetId(OPTION_CHECK_SET_ID)
.checked(checked)
.build());
}
private static class SetupFragment extends GuidedStepFragment {
@Override
public Guidance onCreateGuidance(Bundle savedInstanceState) {
String title = getString(R.string.guidedstep_second_title);
String breadcrumb = getString(R.string.guidedstep_second_breadcrumb);
String description = getString(R.string.guidedstep_second_description);
Drawable icon = getActivity().getDrawable(R.drawable.ic_main_icon);
return new Guidance(title, description, breadcrumb, icon);
}
@Override
public GuidanceStylist onCreateGuidanceStylist() {
return new GuidanceStylist() {
@Override
public int onProvideLayoutId() {
return R.layout.guidedstep_second_guidance;
}
};
}
@Override
public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
for (int i = 0; i < OPTION_NAMES.length; i++) {
boolean checked = false;
if (OPTION_IDS[i] == ACTION_ID_SWITCH_LEGACY_ON) {
if (DetailsActivity.USE_LEGACY_PRESENTER) {
checked = true;
}
} else if (OPTION_IDS[i] == ACTION_ID_SWITCH_LEGACY_OFF) {
if (!DetailsActivity.USE_LEGACY_PRESENTER) {
checked = true;
}
}
addCheckedAction(actions, getActivity(), OPTION_IDS[i], OPTION_NAMES[i],
OPTION_DESCRIPTIONS[i], checked);
}
}
@Override
public void onGuidedActionClicked(GuidedAction action) {
if (action.getId() == ACTION_ID_SWITCH_LEGACY_ON) {
DetailsActivity.USE_LEGACY_PRESENTER = action.isChecked();
} else if (action.getId() == ACTION_ID_SWITCH_LEGACY_OFF) {
DetailsActivity.USE_LEGACY_PRESENTER = !action.isChecked();
}
getActivity().finish();
}
}
}

View File

@@ -57,6 +57,10 @@ public class MainActivity extends Activity {
addAction(actions, BrowseActivity.class, R.string.browse, R.string.browse_description);
addAction(actions, SearchActivity.class, R.string.search, R.string.search_description);
addAction(actions, DetailsActivity.class, R.string.details, R.string.details_description);
actions.get(actions.size()-1).getIntent().putExtra(DetailsActivity.EXTRA_ITEM,
new PhotoItem("Hello world", R.drawable.gallery_photo_1));
addAction(actions, SearchDetailsActivity.class, R.string.search_details,
R.string.search_details_description);
actions.get(actions.size()-1).getIntent().putExtra(DetailsActivity.EXTRA_ITEM,
new PhotoItem("Hello world", R.drawable.gallery_photo_1));
addAction(actions, PlaybackOverlayActivity.class, R.string.playback,
@@ -69,6 +73,9 @@ public class MainActivity extends Activity {
R.string.guidedstep_description);
addAction(actions, BrowseErrorActivity.class, R.string.browseerror,
R.string.browseerror_description);
addAction(actions, DetailsPresenterSelectionActivity.class,
R.string.detail_presenter_options,
R.string.detail_presenter_options_description);
}
private void addAction(List<GuidedAction> actions, Class cls, int titleRes, int descRes) {

View File

@@ -0,0 +1,254 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.example.android.leanback;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ActivityOptionsCompat;
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.ImageCardView;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.ListRowPresenter;
import android.support.v17.leanback.widget.OnActionClickedListener;
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.support.v17.leanback.widget.SparseArrayObjectAdapter;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class NewDetailsFragment extends android.support.v17.leanback.app.DetailsFragment {
private static final String TAG = "leanback.DetailsFragment";
private static final String ITEM = "item";
private static final int NUM_ROWS = 3;
private ArrayObjectAdapter mRowsAdapter;
private PhotoItem mPhotoItem;
final CardPresenter cardPresenter = new CardPresenter();
private BackgroundHelper mBackgroundHelper = new BackgroundHelper();
private static final int ACTION_PLAY = 1;
private static final int ACTION_RENT = 2;
private static final int ACTION_BUY = 3;
private boolean TEST_OVERVIEW_ROW_ON_SECOND;
private boolean TEST_SHARED_ELEMENT_TRANSITION;
private boolean TEST_ENTRANCE_TRANSITION;
private static final long TIME_TO_LOAD_OVERVIEW_ROW_MS = 1000;
private static final long TIME_TO_LOAD_RELATED_ROWS_MS = 2000;
private Action mActionPlay;
private Action mActionRent;
private Action mActionBuy;
private FullWidthDetailsOverviewSharedElementHelper mHelper;
private void initializeTest() {
Activity activity = getActivity();
TEST_SHARED_ELEMENT_TRANSITION = null != activity.getWindow().getSharedElementEnterTransition();
TEST_OVERVIEW_ROW_ON_SECOND = !TEST_SHARED_ELEMENT_TRANSITION;
TEST_ENTRANCE_TRANSITION = true;
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
initializeTest();
setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
setTitle("Leanback Sample App");
setOnSearchClickedListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), SearchActivity.class);
startActivity(intent);
}
});
mActionPlay = new Action(ACTION_PLAY, "Play");
mActionRent = new Action(ACTION_RENT, "Rent", "$3.99",
getResources().getDrawable(R.drawable.ic_action_a));
mActionBuy = new Action(ACTION_BUY, "Buy $9.99");
ClassPresenterSelector ps = new ClassPresenterSelector();
FullWidthDetailsOverviewRowPresenter dorPresenter =
new FullWidthDetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
@Override
public void onActionClicked(Action action) {
Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
int indexOfOverviewRow = TEST_OVERVIEW_ROW_ON_SECOND ? 1 : 0;
DetailsOverviewRow dor = (DetailsOverviewRow) mRowsAdapter.get(indexOfOverviewRow);
if (action.getId() == ACTION_BUY) {
// on the UI thread, we can modify actions adapter directly
SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
dor.getActionsAdapter();
actions.set(ACTION_PLAY, mActionPlay);
actions.clear(ACTION_RENT);
actions.clear(ACTION_BUY);
dor.setItem(mPhotoItem.getTitle() + "(Owned)");
dor.setImageDrawable(getResources().getDrawable(R.drawable.details_img_16x9));
} else if (action.getId() == ACTION_RENT) {
// on the UI thread, we can modify actions adapter directly
SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
dor.getActionsAdapter();
actions.set(ACTION_PLAY, mActionPlay);
actions.clear(ACTION_RENT);
dor.setItem(mPhotoItem.getTitle() + "(Rented)");
} else if (action.getId() == ACTION_PLAY) {
Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class);
getActivity().startActivity(intent);
}
}
});
if (TEST_OVERVIEW_ROW_ON_SECOND) {
dorPresenter.setInitialState(FullWidthDetailsOverviewRowPresenter.STATE_SMALL);
}
ps.addClassPresenter(DetailsOverviewRow.class, dorPresenter);
ps.addClassPresenter(ListRow.class, new ListRowPresenter());
mRowsAdapter = new ArrayObjectAdapter(ps);
PhotoItem item = (PhotoItem) (savedInstanceState != null ?
savedInstanceState.getParcelable(ITEM) : null);
if (item != null) {
setItem(item);
}
setOnItemViewClickedListener(new OnItemViewClickedListener() {
@Override
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
Log.i(TAG, "onItemClicked: " + item + " row " + row);
if (item instanceof PhotoItem){
Intent intent = new Intent(getActivity(), DetailsActivity.class);
intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
getActivity(),
((ImageCardView)itemViewHolder.view).getMainImageView(),
DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
getActivity().startActivity(intent, bundle);
}
}
});
setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
@Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
Log.i(TAG, "onItemSelected: " + item + " row " + row);
}
});
if (TEST_SHARED_ELEMENT_TRANSITION) {
mHelper = new FullWidthDetailsOverviewSharedElementHelper();
mHelper.setSharedElementEnterTransition(getActivity(),
DetailsActivity.SHARED_ELEMENT_NAME);
dorPresenter.setListener(mHelper);
dorPresenter.setParticipatingEntranceTransition(false);
} else {
dorPresenter.setParticipatingEntranceTransition(true);
}
if (TEST_ENTRANCE_TRANSITION) {
// don't run entrance transition if Activity is restored.
if (savedInstanceState == null) {
prepareEntranceTransition();
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(ITEM, mPhotoItem);
}
public void setItem(PhotoItem photoItem) {
mPhotoItem = photoItem;
mRowsAdapter.clear();
new Handler().postDelayed(new Runnable() {
public void run() {
if (TEST_OVERVIEW_ROW_ON_SECOND) {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
HeaderItem header = new HeaderItem(0, "Search Result");
mRowsAdapter.add(0, new ListRow(header, listRowAdapter));
}
Resources res = getActivity().getResources();
DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
adapter.set(ACTION_RENT, mActionRent);
adapter.set(ACTION_BUY, mActionBuy);
dor.setActionsAdapter(adapter);
int indexOfOverviewRow = TEST_OVERVIEW_ROW_ON_SECOND ? 1 : 0;
mRowsAdapter.add(indexOfOverviewRow, dor);
setSelectedPosition(0, true);
if (TEST_SHARED_ELEMENT_TRANSITION) {
if (mHelper != null && !mHelper.getAutoStartSharedElementTransition()) {
mHelper.startPostponedEnterTransition();
}
}
}
}, TIME_TO_LOAD_OVERVIEW_ROW_MS);
new Handler().postDelayed(new Runnable() {
public void run() {
for (int i = 0; i < NUM_ROWS; ++i) {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
HeaderItem header = new HeaderItem(i, "Row " + i);
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}
if (TEST_ENTRANCE_TRANSITION) {
startEntranceTransition();
}
}
}, TIME_TO_LOAD_RELATED_ROWS_MS);
setAdapter(mRowsAdapter);
}
@Override
public void onStart() {
super.onStart();
if (mPhotoItem != null) {
mBackgroundHelper.setBackground(
getActivity(), mPhotoItem.getImageResourceId());
}
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.example.android.leanback;
/**
* Same implementation as DetailsActivity for different entries in AndroidManifest.
*/
public class SearchDetailsActivity extends DetailsActivity
{
}