165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko/*
265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Copyright (C) 2016 The Android Open Source Project
365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *
465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * you may not use this file except in compliance with the License.
665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * You may obtain a copy of the License at
765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *
865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *
1065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Unless required by applicable law or agreed to in writing, software
1165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
1265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * See the License for the specific language governing permissions and
1465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * limitations under the License
1565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */
1665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.dvr.ui;
1865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
1965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.content.Context;
2065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.content.Intent;
2165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.graphics.Point;
2265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.hardware.display.DisplayManager;
2365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.media.tv.TvContentRating;
2465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.os.Bundle;
2565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.media.session.PlaybackState;
2665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.media.tv.TvInputManager;
2765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.media.tv.TvView;
2865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.app.PlaybackOverlayFragment;
2965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.widget.ArrayObjectAdapter;
3065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.widget.ClassPresenterSelector;
3165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.widget.HeaderItem;
3265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.widget.ListRow;
3365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.widget.ListRowPresenter;
3465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.widget.PlaybackControlsRow;
3565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
36d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.support.v17.leanback.widget.SinglePresenterSelector;
3765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.view.Display;
3865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.view.View;
3965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.view.ViewGroup;
4065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.widget.Toast;
4165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.text.TextUtils;
4265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.util.Log;
4365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
4465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.R;
4565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.TvApplication;
46d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport com.android.tv.data.BaseProgram;
4765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dvr.RecordedProgram;
4865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dialog.PinDialogFragment;
4965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dvr.DvrDataManager;
5065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dvr.DvrPlayer;
5165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dvr.DvrPlaybackMediaSessionHelper;
5265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.parental.ContentRatingsManager;
5365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.util.Utils;
5465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
5565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopublic class DvrPlaybackOverlayFragment extends PlaybackOverlayFragment {
5665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    // TODO: Handles audio focus. Deals with block and ratings.
5765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final String TAG = "DvrPlaybackOverlayFragment";
5865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final boolean DEBUG = false;
5965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
6065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final String MEDIA_SESSION_TAG = "com.android.tv.dvr.mediasession";
6165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final float DISPLAY_ASPECT_RATIO_EPSILON = 0.01f;
6265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
6365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    // mProgram is only used to store program from intent. Don't use it elsewhere.
6465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private RecordedProgram mProgram;
6565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private DvrPlaybackMediaSessionHelper mMediaSessionHelper;
6665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private DvrPlaybackControlHelper mPlaybackControlHelper;
6765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private ArrayObjectAdapter mRowsAdapter;
68d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private SortedArrayAdapter<BaseProgram> mRelatedRecordingsRowAdapter;
69d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private DvrPlaybackCardPresenter mRelatedRecordingCardPresenter;
7065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private DvrDataManager mDvrDataManager;
7165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private ContentRatingsManager mContentRatingsManager;
7265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private TvView mTvView;
7365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private View mBlockScreenView;
7465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private ListRow mRelatedRecordingsRow;
7565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private int mExtraPaddingNoRelatedRow;
7665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private int mWindowWidth;
7765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private int mWindowHeight;
7865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private float mAppliedAspectRatio;
7965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private float mWindowAspectRatio;
8065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private boolean mPinChecked;
8165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
8265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @Override
8365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void onCreate(Bundle savedInstanceState) {
8465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (DEBUG) Log.d(TAG, "onCreate");
8565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        super.onCreate(savedInstanceState);
8665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mExtraPaddingNoRelatedRow = getActivity().getResources()
8765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                .getDimensionPixelOffset(R.dimen.dvr_playback_fragment_extra_padding_top);
8865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mDvrDataManager = TvApplication.getSingletons(getActivity()).getDvrDataManager();
8965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mContentRatingsManager = TvApplication.getSingletons(getContext())
9065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                .getTvInputManagerHelper().getContentRatingsManager();
9165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mProgram = getProgramFromIntent(getActivity().getIntent());
9265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mProgram == null) {
9365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Toast.makeText(getActivity(), getString(R.string.dvr_program_not_found),
9465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    Toast.LENGTH_SHORT).show();
9565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            getActivity().finish();
9665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
9765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
9865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        Point size = new Point();
9965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE))
10065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                .getDisplay(Display.DEFAULT_DISPLAY).getSize(size);
10165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWindowWidth = size.x;
10265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWindowHeight = size.y;
10365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWindowAspectRatio = mAppliedAspectRatio = (float) mWindowWidth / mWindowHeight;
10465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        setBackgroundType(PlaybackOverlayFragment.BG_LIGHT);
10565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        setFadingEnabled(true);
10665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
10765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
10865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @Override
10965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void onActivityCreated(Bundle savedInstanceState) {
11065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        super.onActivityCreated(savedInstanceState);
11165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mTvView = (TvView) getActivity().findViewById(R.id.dvr_tv_view);
11265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mBlockScreenView = getActivity().findViewById(R.id.block_screen);
11365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mMediaSessionHelper = new DvrPlaybackMediaSessionHelper(
114d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                getActivity(), MEDIA_SESSION_TAG, new DvrPlayer(mTvView), this);
11565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mPlaybackControlHelper = new DvrPlaybackControlHelper(getActivity(), this);
11665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        setUpRows();
11765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        preparePlayback(getActivity().getIntent());
11865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        DvrPlayer dvrPlayer = mMediaSessionHelper.getDvrPlayer();
11965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        dvrPlayer.setAspectRatioChangedListener(new DvrPlayer.AspectRatioChangedListener() {
12065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            @Override
12165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            public void onAspectRatioChanged(float videoAspectRatio) {
12265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                updateAspectRatio(videoAspectRatio);
12365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
12465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        });
12565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mPinChecked = getActivity().getIntent()
12665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                .getBooleanExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_PIN_CHECKED, false);
12765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        dvrPlayer.setContentBlockedListener(new DvrPlayer.ContentBlockedListener() {
12865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            @Override
12965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            public void onContentBlocked(TvContentRating rating) {
13065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (mPinChecked) {
13165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    mTvView.unblockContent(rating);
13265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    return;
13365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
13465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mBlockScreenView.setVisibility(View.VISIBLE);
13565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                getActivity().getMediaController().getTransportControls().pause();
13665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                new PinDialogFragment(PinDialogFragment.PIN_DIALOG_TYPE_UNLOCK_DVR,
13765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                        new PinDialogFragment.ResultListener() {
13865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                            @Override
13965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                            public void done(boolean success) {
14065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                                if (success) {
14165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                                    mPinChecked = true;
14265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                                    mTvView.unblockContent(rating);
14365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                                    mBlockScreenView.setVisibility(View.GONE);
14465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                                    getActivity().getMediaController()
14565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                                            .getTransportControls().play();
14665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                                }
14765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                            }
14865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                        }, mContentRatingsManager.getDisplayNameForRating(rating))
14965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                        .show(getActivity().getFragmentManager(), PinDialogFragment.DIALOG_TAG);
15065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
15165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            });
15265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
15365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
15465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @Override
15565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void onPause() {
15665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (DEBUG) Log.d(TAG, "onPause");
15765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        super.onPause();
15865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_FAST_FORWARDING
15965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                || mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_REWINDING) {
16065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            getActivity().getMediaController().getTransportControls().pause();
16165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
16265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_NONE) {
16365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            getActivity().requestVisibleBehind(false);
16465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        } else {
16565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            getActivity().requestVisibleBehind(true);
16665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
16765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
16865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
16965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @Override
17065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void onDestroy() {
17165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (DEBUG) Log.d(TAG, "onDestroy");
17265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mPlaybackControlHelper.unregisterCallback();
17365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mMediaSessionHelper.release();
174d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        mRelatedRecordingCardPresenter.unbindAllViewHolders();
175d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        super.onDestroy();
17665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
17765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
17865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
17965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Passes the intent to the fragment.
18065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
18165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void onNewIntent(Intent intent) {
18265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mProgram = getProgramFromIntent(intent);
18365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mProgram == null) {
18465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Toast.makeText(getActivity(), getString(R.string.dvr_program_not_found),
18565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    Toast.LENGTH_SHORT).show();
18665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            // Continue playing the original program
18765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
18865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
18965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        preparePlayback(intent);
19065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
19165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
19265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
19365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Should be called when windows' size is changed in order to notify DVR player
19465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * to update it's view width/height and position.
19565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
19665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void onWindowSizeChanged(final int windowWidth, final int windowHeight) {
19765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWindowWidth = windowWidth;
19865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWindowHeight = windowHeight;
19965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWindowAspectRatio = (float) mWindowWidth / mWindowHeight;
20065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        updateAspectRatio(mAppliedAspectRatio);
20165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
20265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
203d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public RecordedProgram getNextEpisode(RecordedProgram program) {
204d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        int position = mRelatedRecordingsRowAdapter.findInsertPosition(program);
205d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (position == mRelatedRecordingsRowAdapter.size()) {
206d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return null;
207d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        } else {
208d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return (RecordedProgram) mRelatedRecordingsRowAdapter.get(position);
209d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
210d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
211d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
21265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    void onMediaControllerUpdated() {
21365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
21465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
21565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
21665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void updateAspectRatio(float videoAspectRatio) {
21765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (Math.abs(mAppliedAspectRatio - videoAspectRatio) < DISPLAY_ASPECT_RATIO_EPSILON) {
21865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            // No need to change
21965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
22065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
22165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (videoAspectRatio < mWindowAspectRatio) {
22265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            int newPadding = (mWindowWidth - Math.round(mWindowHeight * videoAspectRatio)) / 2;
22365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            ((ViewGroup) mTvView.getParent()).setPadding(newPadding, 0, newPadding, 0);
22465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        } else {
22565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            int newPadding = (mWindowHeight - Math.round(mWindowWidth / videoAspectRatio)) / 2;
22665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            ((ViewGroup) mTvView.getParent()).setPadding(0, newPadding, 0, newPadding);
22765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
22865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mAppliedAspectRatio = videoAspectRatio;
22965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
23065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
23165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void preparePlayback(Intent intent) {
23265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mMediaSessionHelper.setupPlayback(mProgram, getSeekTimeFromIntent(intent));
23365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        getActivity().getMediaController().getTransportControls().prepare();
23465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        updateRelatedRecordingsRow();
23565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
23665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
23765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void updateRelatedRecordingsRow() {
23865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        boolean wasEmpty = (mRelatedRecordingsRowAdapter.size() == 0);
23965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mRelatedRecordingsRowAdapter.clear();
24065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        long programId = mProgram.getId();
24165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        String seriesId = mProgram.getSeriesId();
24265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!TextUtils.isEmpty(seriesId)) {
24365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (DEBUG) Log.d(TAG, "Update related recordings with:" + seriesId);
24465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            for (RecordedProgram program : mDvrDataManager.getRecordedPrograms()) {
24565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (seriesId.equals(program.getSeriesId()) && programId != program.getId()) {
24665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    mRelatedRecordingsRowAdapter.add(program);
24765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
24865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
24965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
25065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        View view = getView();
25165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mRelatedRecordingsRowAdapter.size() == 0) {
25265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mRowsAdapter.remove(mRelatedRecordingsRow);
25365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            view.setPadding(view.getPaddingLeft(), mExtraPaddingNoRelatedRow,
25465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    view.getPaddingRight(), view.getPaddingBottom());
25565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        } else if (wasEmpty){
25665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mRowsAdapter.add(mRelatedRecordingsRow);
25765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            view.setPadding(view.getPaddingLeft(), 0,
25865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    view.getPaddingRight(), view.getPaddingBottom());
25965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
26065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
26165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
26265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void setUpRows() {
26365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        PlaybackControlsRowPresenter controlsRowPresenter =
26465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mPlaybackControlHelper.createControlsRowAndPresenter();
26565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
26665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        ClassPresenterSelector selector = new ClassPresenterSelector();
26765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        selector.addClassPresenter(PlaybackControlsRow.class, controlsRowPresenter);
26865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
26965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
27065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mRowsAdapter = new ArrayObjectAdapter(selector);
27165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mRowsAdapter.add(mPlaybackControlHelper.getControlsRow());
27265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mRelatedRecordingsRow = getRelatedRecordingsRow();
27365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        setAdapter(mRowsAdapter);
27465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
27565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
27665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private ListRow getRelatedRecordingsRow() {
277d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        mRelatedRecordingCardPresenter = new DvrPlaybackCardPresenter(getActivity());
278d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        mRelatedRecordingsRowAdapter = new RelatedRecordingsAdapter(mRelatedRecordingCardPresenter);
27965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        HeaderItem header = new HeaderItem(0,
28065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                getActivity().getString(R.string.dvr_playback_related_recordings));
28165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return new ListRow(header, mRelatedRecordingsRowAdapter);
28265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
28365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
28465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private RecordedProgram getProgramFromIntent(Intent intent) {
28565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        long programId = intent.getLongExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, -1);
28665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mDvrDataManager.getRecordedProgram(programId);
28765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
28865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
28965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private long getSeekTimeFromIntent(Intent intent) {
29065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return intent.getLongExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_SEEK_TIME,
29165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                TvInputManager.TIME_SHIFT_INVALID_TIME);
29265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
293d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
294d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private class RelatedRecordingsAdapter extends SortedArrayAdapter<BaseProgram> {
295d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        RelatedRecordingsAdapter(DvrPlaybackCardPresenter presenter) {
296d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            super(new SinglePresenterSelector(presenter), BaseProgram.EPISODE_COMPARATOR);
297d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
298d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
299d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        @Override
300d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        long getId(BaseProgram item) {
301d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return item.getId();
302d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
303d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
30465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko}