1ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu/*
2ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * Copyright (C) 2016 The Android Open Source Project
3ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu *
4ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * Licensed under the Apache License, Version 2.0 (the "License");
5ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * you may not use this file except in compliance with the License.
6ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * You may obtain a copy of the License at
7ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu *
8ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu *      http://www.apache.org/licenses/LICENSE-2.0
9ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu *
10ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * Unless required by applicable law or agreed to in writing, software
11ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * distributed under the License is distributed on an "AS IS" BASIS,
12ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * See the License for the specific language governing permissions and
14ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu * limitations under the License.
15ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu */
16ad3fd6c48f41ef20e63da40c626b053620526cccDake Gupackage android.support.v17.leanback.app;
17ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
18ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.content.Context;
19ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.graphics.drawable.Drawable;
20ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.os.Bundle;
21ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.os.Handler;
22ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.test.R;
23ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.Action;
24ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.ArrayObjectAdapter;
255a4d3a98d681cc9042b28a923aa5a23a6b961998Dake Guimport android.support.v17.leanback.widget.ClassPresenterSelector;
26ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.ControlButtonPresenterSelector;
27ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.HeaderItem;
28ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.ListRow;
29ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.ListRowPresenter;
30ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.OnItemViewClickedListener;
31ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.OnItemViewSelectedListener;
32ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.PlaybackControlsRow;
33ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
34ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.Presenter;
35ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.PresenterSelector;
36ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.Row;
37ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.RowPresenter;
38ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.support.v17.leanback.widget.SparseArrayObjectAdapter;
39ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.util.Log;
40ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.view.KeyEvent;
41ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.view.View;
42ad3fd6c48f41ef20e63da40c626b053620526cccDake Guimport android.widget.Toast;
43ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
44f37579e64940bfdd642cc315f6347d60b5addd69Dake Gupublic class PlaybackOverlayTestFragment extends PlaybackOverlayFragment {
45ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private static final String TAG = "leanback.PlaybackControlsFragment";
46ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
47ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    /**
48ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu     * Change this to choose a different overlay background.
49ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu     */
50ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
51ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
52ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    /**
53ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu     * Change the number of related content rows.
54ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu     */
55ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private static final int RELATED_CONTENT_ROWS = 3;
56ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
57ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    /**
58ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu     * Change this to select hidden
59ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu     */
60ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private static final boolean SECONDARY_HIDDEN = false;
61ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
62ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private static final int ROW_CONTROLS = 0;
63ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
64ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private PlaybackControlHelper mGlue;
65ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
66ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
67ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
68ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
69ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
70ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                                  RowPresenter.ViewHolder rowViewHolder, Row row) {
71ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            Log.i(TAG, "onItemClicked: " + item + " row " + row);
72ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (item instanceof Action) {
73ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                mGlue.onActionClicked((Action) item);
74ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
75ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
76ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    };
77ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
78ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private OnItemViewSelectedListener mOnItemViewSelectedListener =
79ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            new OnItemViewSelectedListener() {
80ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
81ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
82ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                                   RowPresenter.ViewHolder rowViewHolder, Row row) {
83ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            Log.i(TAG, "onItemSelected: " + item + " row " + row);
84ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
85ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    };
86ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
87e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
88ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    public SparseArrayObjectAdapter getAdapter() {
89ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        return (SparseArrayObjectAdapter) super.getAdapter();
90ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    }
91ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
92ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    @Override
93ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    public void onCreate(Bundle savedInstanceState) {
94ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        Log.i(TAG, "onCreate");
95ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        super.onCreate(savedInstanceState);
96ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
97ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        setBackgroundType(BACKGROUND_TYPE);
98ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
99ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
100ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        createComponents(getActivity());
101ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    }
102ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
103ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    private void createComponents(Context context) {
104ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        mGlue = new PlaybackControlHelper(context, this) {
105ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            @Override
106ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            public int getUpdatePeriod() {
1073bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                long totalTime = getControlsRow().getDuration();
108ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                if (getView() == null || getView().getWidth() == 0 || totalTime <= 0) {
109ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    return 1000;
110ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                }
1113bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                return 16;
112ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
113ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
114ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            @Override
115ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            protected void onRowChanged(PlaybackControlsRow row) {
116ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                if (getAdapter() == null) {
117ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    return;
118ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                }
119ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                int index = getAdapter().indexOf(row);
120ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                if (index >= 0) {
121ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    getAdapter().notifyArrayItemRangeChanged(index, 1);
122ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                }
123ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
124ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
125ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            @Override
126ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            public void onActionClicked(Action action) {
127ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                if (action.getId() == R.id.lb_control_picture_in_picture) {
128ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    getActivity().enterPictureInPictureMode();
129ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    return;
130ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                }
131ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                super.onActionClicked(action);
132ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
133ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        };
134ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
135ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
136ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
137ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
138ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
1395a4d3a98d681cc9042b28a923aa5a23a6b961998Dake Gu        ClassPresenterSelector selector = new ClassPresenterSelector();
1405a4d3a98d681cc9042b28a923aa5a23a6b961998Dake Gu        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
1415a4d3a98d681cc9042b28a923aa5a23a6b961998Dake Gu        selector.addClassPresenter(PlaybackControlsRow.class, mPlaybackControlsRowPresenter);
142ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
1435a4d3a98d681cc9042b28a923aa5a23a6b961998Dake Gu        setAdapter(new SparseArrayObjectAdapter(selector));
144ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
145ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        // Add the controls row
146ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
147ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
148ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        // Add related content rows
149ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
150ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
151ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            listRowAdapter.add("Some related content");
152ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            listRowAdapter.add("Other related content");
153ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            HeaderItem header = new HeaderItem(i, "Row " + i);
154ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
155ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
156ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
157ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    }
158ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
159ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    @Override
160ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    public void onStart() {
161ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        super.onStart();
162ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        mGlue.setFadingEnabled(true);
163ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    }
164ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
165ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    abstract static class PlaybackControlHelper extends PlaybackControlGlue {
166ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        /**
167ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu         * Change the location of the thumbs up/down controls
168ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu         */
169ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private static final boolean THUMBS_PRIMARY = true;
170ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
171ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private static final String FAUX_TITLE = "A short song of silence";
172ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private static final String FAUX_SUBTITLE = "2014";
173ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private static final int FAUX_DURATION = 33 * 1000;
174ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
175ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        // These should match the playback service FF behavior
176ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private static int[] sFastForwardSpeeds = { 2, 3, 4, 5 };
177ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
178ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private boolean mIsPlaying;
179ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private int mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
180ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private long mStartTime;
181ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private long mStartPosition = 0;
182ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
183ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private PlaybackControlsRow.RepeatAction mRepeatAction;
184ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
185ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
186ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private PlaybackControlsRow.PictureInPictureAction mPipAction;
1874702556bfd15c9819a7b2af759aee0f719cd631fsusnata        private static Handler mHandler = new Handler();
188ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
189ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private final Runnable mUpdateProgressRunnable = new Runnable() {
190ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            @Override
191ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            public void run() {
192ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                updateProgress();
193ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                mHandler.postDelayed(this, getUpdatePeriod());
194ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
195ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        };
196ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
197ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        PlaybackControlHelper(Context context, PlaybackOverlayFragment fragment) {
198ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            super(context, fragment, sFastForwardSpeeds);
199ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
200946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu            mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.INDEX_OUTLINE);
201ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
202946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu            mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.INDEX_OUTLINE);
203ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
204ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mPipAction = new PlaybackControlsRow.PictureInPictureAction(context);
205ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
206ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
207ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
208ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
209ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
210ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
211ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            ArrayObjectAdapter adapter = new ArrayObjectAdapter(
212ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    new ControlButtonPresenterSelector());
213ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            getControlsRow().setSecondaryActionsAdapter(adapter);
214ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (!THUMBS_PRIMARY) {
215ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                adapter.add(mThumbsDownAction);
216ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
217ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (android.os.Build.VERSION.SDK_INT > 23) {
218ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                adapter.add(mPipAction);
219ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
220ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            adapter.add(mRepeatAction);
221ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (!THUMBS_PRIMARY) {
222ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                adapter.add(mThumbsUpAction);
223ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
224ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
225ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return presenter;
226ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
227ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
228ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
229ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
230ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                PresenterSelector presenterSelector) {
231ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
232ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (THUMBS_PRIMARY) {
233ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                adapter.set(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
234ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                adapter.set(PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
235ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
236ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return adapter;
237ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
238ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
239ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
240ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public void onActionClicked(Action action) {
241ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (shouldDispatchAction(action)) {
242ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                dispatchAction(action);
243ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                return;
244ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
245ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            super.onActionClicked(action);
246ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
247ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
248ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
249ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
250ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
251ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                Action action = getControlsRow().getActionForKeyCode(keyEvent.getKeyCode());
252ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                if (shouldDispatchAction(action)) {
253ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    dispatchAction(action);
254ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    return true;
255ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                }
256ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
257ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return super.onKey(view, keyCode, keyEvent);
258ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
259ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
260ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private boolean shouldDispatchAction(Action action) {
261ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return action == mRepeatAction || action == mThumbsUpAction
262ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    || action == mThumbsDownAction;
263ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
264ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
265ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private void dispatchAction(Action action) {
266ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show();
267ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
268ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            multiAction.nextIndex();
269ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            notifyActionChanged(multiAction);
270ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
271ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
272ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
273ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            int index;
274ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            index = getPrimaryActionsAdapter().indexOf(action);
275ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (index >= 0) {
276ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
277ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            } else {
278ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                index = getSecondaryActionsAdapter().indexOf(action);
279ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                if (index >= 0) {
280ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
281ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                }
282ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
283ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
284ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
285ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
286ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter();
287ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
288ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
289ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        private ArrayObjectAdapter getSecondaryActionsAdapter() {
290ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter();
291ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
292ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
293ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
294ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public boolean hasValidMedia() {
295ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return true;
296ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
297ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
298ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
299ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public boolean isMediaPlaying() {
300ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return mIsPlaying;
301ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
302ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
303ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
304ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public CharSequence getMediaTitle() {
305ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return FAUX_TITLE;
306ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
307ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
308ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
309ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public CharSequence getMediaSubtitle() {
310ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return FAUX_SUBTITLE;
311ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
312ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
313ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
314ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public int getMediaDuration() {
315ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return FAUX_DURATION;
316ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
317ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
318ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
319ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public Drawable getMediaArt() {
320ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return null;
321ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
322ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
323ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
324ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public long getSupportedActions() {
325ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return PlaybackControlGlue.ACTION_PLAY_PAUSE
326ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                   | PlaybackControlGlue.ACTION_FAST_FORWARD
327ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                   | PlaybackControlGlue.ACTION_REWIND;
328ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
329ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
330ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
331ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public int getCurrentSpeedId() {
332ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return mSpeed;
333ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
334ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
335ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
336ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public int getCurrentPosition() {
337ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            int speed;
338ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
339ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                speed = 0;
340ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            } else if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_NORMAL) {
341ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                speed = 1;
342ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            } else if (mSpeed >= PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
343ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                int index = mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
344ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                speed = getFastForwardSpeeds()[index];
345ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            } else if (mSpeed <= -PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
346ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                int index = -mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
347ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                speed = -getRewindSpeeds()[index];
348ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            } else {
349ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                return -1;
350ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
351ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            long position = mStartPosition + (System.currentTimeMillis() - mStartTime) * speed;
352ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (position > getMediaDuration()) {
353ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                position = getMediaDuration();
354ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                onPlaybackComplete(true);
355ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            } else if (position < 0) {
356ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                position = 0;
357ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                onPlaybackComplete(false);
358ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
359ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            return (int) position;
360ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
361ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
362ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        void onPlaybackComplete(final boolean ended) {
363ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mHandler.post(new Runnable() {
364ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                @Override
365ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                public void run() {
366946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu                    if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.INDEX_NONE) {
367ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                        pausePlayback();
368ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    } else {
369ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                        startPlayback(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
370ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    }
371ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    mStartPosition = 0;
372ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                    onStateChanged();
373ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                }
374ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            });
375ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
376ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
377ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
378ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        protected void startPlayback(int speed) {
379ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (speed == mSpeed) {
380ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                return;
381ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
382ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mStartPosition = getCurrentPosition();
383ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mSpeed = speed;
384ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mIsPlaying = true;
385ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mStartTime = System.currentTimeMillis();
386ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
387ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
388ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
389ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        protected void pausePlayback() {
390ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
391ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                return;
392ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
393ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mStartPosition = getCurrentPosition();
394ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
395ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mIsPlaying = false;
396ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
397ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
398ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
399ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        protected void skipToNext() {
400ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            // Not supported
401ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
402ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
403ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
404ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        protected void skipToPrevious() {
405ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            // Not supported
406ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
407ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu
408ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        @Override
409ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        public void enableProgressUpdating(boolean enable) {
410ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            mHandler.removeCallbacks(mUpdateProgressRunnable);
411ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            if (enable) {
412ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu                mUpdateProgressRunnable.run();
413ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu            }
414ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu        }
415ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu    }
416ad3fd6c48f41ef20e63da40c626b053620526cccDake Gu}
417