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