1a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin/* 2a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Copyright (C) 2017 The Android Open Source Project 3a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 4a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Licensed under the Apache License, Version 2.0 (the "License"); 5a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * you may not use this file except in compliance with the License. 6a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * You may obtain a copy of the License at 7a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 8a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * http://www.apache.org/licenses/LICENSE-2.0 9a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 10a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Unless required by applicable law or agreed to in writing, software 11a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * distributed under the License is distributed on an "AS IS" BASIS, 12a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * See the License for the specific language governing permissions and 14a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * limitations under the License. 15a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 16a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 17a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinpackage android.support.v17.leanback.media; 18a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 19a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.content.Context; 20a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.graphics.drawable.Drawable; 21a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.annotation.CallSuper; 22a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.Action; 23a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.ArrayObjectAdapter; 24a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.ControlButtonPresenterSelector; 25a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.OnActionClickedListener; 26a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.PlaybackControlsRow; 27a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.PlaybackRowPresenter; 28a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.PlaybackTransportRowPresenter; 29a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.support.v17.leanback.widget.Presenter; 30a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.text.TextUtils; 31a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.util.Log; 32a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.view.KeyEvent; 33a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport android.view.View; 34a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 35a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinimport java.util.List; 36a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 37a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin/** 38a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * A base abstract class for managing a {@link PlaybackControlsRow} being displayed in 39a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link PlaybackGlueHost}. It supports standard playback control actions play/pause and 40a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * skip next/previous. This helper class is a glue layer that manages interaction between the 41a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * leanback UI components {@link PlaybackControlsRow} {@link PlaybackRowPresenter} 42a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * and a functional {@link PlayerAdapter} which represents the underlying 43a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * media player. 44a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 45a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * <p>The app must pass a {@link PlayerAdapter} in constructor for a specific 46a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * implementation e.g. a {@link MediaPlayerAdapter}. 47a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * </p> 48a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 49a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * <p>The glue has two action bars: primary action bars and secondary action bars. Apps 50a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * can provide additional actions by overriding {@link #onCreatePrimaryActions} and / or 51a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link #onCreateSecondaryActions} and respond to actions by overriding 52a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link #onActionClicked(Action)}. 53a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * </p> 54a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 55a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * <p>The subclass is responsible for implementing the "repeat mode" in 56a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link #onPlayCompleted()}. 57a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * </p> 58a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 59a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param <T> Type of {@link PlayerAdapter} passed in constructor. 60a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 61a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsinpublic abstract class PlaybackBaseControlGlue<T extends PlayerAdapter> extends PlaybackGlue 62a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin implements OnActionClickedListener, View.OnKeyListener { 63a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 64a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin static final String TAG = "PlaybackTransportGlue"; 65a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin static final boolean DEBUG = false; 66a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 67a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin final T mPlayerAdapter; 68a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackControlsRow mControlsRow; 69a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackRowPresenter mControlsRowPresenter; 70a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackControlsRow.PlayPauseAction mPlayPauseAction; 71a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin boolean mIsPlaying = false; 72a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin boolean mFadeWhenPlaying = true; 73a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 74a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin CharSequence mSubtitle; 75a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin CharSequence mTitle; 76a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin Drawable mCover; 77a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 78a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackGlueHost.PlayerCallback mPlayerCallback; 79a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin boolean mBuffering = false; 80a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin int mVideoWidth = 0; 81a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin int mVideoHeight = 0; 82a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin boolean mErrorSet = false; 83a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin int mErrorCode; 84a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin String mErrorMessage; 85a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 86a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin final PlayerAdapter.Callback mAdapterCallback = new PlayerAdapter 87a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin .Callback() { 88a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 89a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 90a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onPlayStateChanged(PlayerAdapter wrapper) { 91a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (DEBUG) Log.v(TAG, "onPlayStateChanged"); 92a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackBaseControlGlue.this.onPlayStateChanged(); 93a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 94a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 95a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 96a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onCurrentPositionChanged(PlayerAdapter wrapper) { 97a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (DEBUG) Log.v(TAG, "onCurrentPositionChanged"); 98a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackBaseControlGlue.this.onUpdateProgress(); 99a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 100a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 101a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 102a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onBufferedPositionChanged(PlayerAdapter wrapper) { 103a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (DEBUG) Log.v(TAG, "onBufferedPositionChanged"); 104a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackBaseControlGlue.this.onUpdateBufferedProgress(); 105a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 106a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 107a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 108a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onDurationChanged(PlayerAdapter wrapper) { 109a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (DEBUG) Log.v(TAG, "onDurationChanged"); 110a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackBaseControlGlue.this.onUpdateDuration(); 111a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 112a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 113a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 114a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onPlayCompleted(PlayerAdapter wrapper) { 115a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (DEBUG) Log.v(TAG, "onPlayCompleted"); 116a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackBaseControlGlue.this.onPlayCompleted(); 117a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 118a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 119a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 120a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onPreparedStateChanged(PlayerAdapter wrapper) { 121a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (DEBUG) Log.v(TAG, "onPreparedStateChanged"); 122a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackBaseControlGlue.this.onPreparedStateChanged(); 123a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 124a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 125a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 126a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onVideoSizeChanged(PlayerAdapter wrapper, int width, int height) { 127a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mVideoWidth = width; 128a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mVideoHeight = height; 129a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mPlayerCallback != null) { 130a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback.onVideoSizeChanged(width, height); 131a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 132a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 133a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 134a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 135a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onError(PlayerAdapter wrapper, int errorCode, String errorMessage) { 136a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mErrorSet = true; 137a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mErrorCode = errorCode; 138a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mErrorMessage = errorMessage; 139a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mPlayerCallback != null) { 140a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback.onError(errorCode, errorMessage); 141a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 142a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 143a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 144a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 145a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void onBufferingStateChanged(PlayerAdapter wrapper, boolean start) { 146a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mBuffering = start; 147a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mPlayerCallback != null) { 148a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback.onBufferingStateChanged(start); 149a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 150a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 151a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin }; 152a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 153a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 154a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Constructor for the glue. 155a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 156a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param context 157a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param impl Implementation to underlying media player. 158a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 159a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public PlaybackBaseControlGlue(Context context, T impl) { 160a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin super(context); 161a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter = impl; 162a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.setCallback(mAdapterCallback); 163a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 164a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 165a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public final T getPlayerAdapter() { 166a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mPlayerAdapter; 167a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 168a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 169a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 170a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onAttachedToHost(PlaybackGlueHost host) { 171a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin super.onAttachedToHost(host); 172a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin host.setOnKeyInterceptListener(this); 173a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin host.setOnActionClickedListener(this); 174a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onCreateDefaultControlsRow(); 175a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onCreateDefaultRowPresenter(); 176a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin host.setPlaybackRowPresenter(getPlaybackRowPresenter()); 177a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin host.setPlaybackRow(getControlsRow()); 178a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 179a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback = host.getPlayerCallback(); 180a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onAttachHostCallback(); 181a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.onAttachedToHost(host); 182a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 183a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 184a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onAttachHostCallback() { 185a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mPlayerCallback != null) { 186a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mVideoWidth != 0 && mVideoHeight != 0) { 187a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback.onVideoSizeChanged(mVideoWidth, mVideoHeight); 188a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 189a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mErrorSet) { 190a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback.onError(mErrorCode, mErrorMessage); 191a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 192a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback.onBufferingStateChanged(mBuffering); 193a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 194a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 195a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 196a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onDetachHostCallback() { 197a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mErrorSet = false; 198a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mErrorCode = 0; 199a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mErrorMessage = null; 200a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mPlayerCallback != null) { 201a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback.onBufferingStateChanged(false); 202a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 203a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 204a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 205a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 206a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onHostStart() { 207a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.setProgressUpdatingEnabled(true); 208a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 209a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 210a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 211a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onHostStop() { 212a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.setProgressUpdatingEnabled(false); 213a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 214a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 215a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 216a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onDetachedFromHost() { 217a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onDetachHostCallback(); 218a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerCallback = null; 219a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.onDetachedFromHost(); 220a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.setProgressUpdatingEnabled(false); 221a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin super.onDetachedFromHost(); 222a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 223a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 224a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onCreateDefaultControlsRow() { 225a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRow == null) { 226a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin PlaybackControlsRow controlsRow = new PlaybackControlsRow(this); 227a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin setControlsRow(controlsRow); 228a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 229a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 230a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 231a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onCreateDefaultRowPresenter() { 232a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRowPresenter == null) { 233a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin setPlaybackRowPresenter(onCreateRowPresenter()); 234a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 235a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 236a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 237a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected abstract PlaybackRowPresenter onCreateRowPresenter(); 238a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 239a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 240a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Sets the controls to auto hide after a timeout when media is playing. 241a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param enable True to enable auto hide after a timeout when media is playing. 242a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @see PlaybackGlueHost#setControlsOverlayAutoHideEnabled(boolean) 243a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 244a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void setControlsOverlayAutoHideEnabled(boolean enable) { 245a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mFadeWhenPlaying = enable; 246a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (!mFadeWhenPlaying && getHost() != null) { 247a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin getHost().setControlsOverlayAutoHideEnabled(false); 248a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 249a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 250a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 251a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 252a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Returns true if the controls auto hides after a timeout when media is playing. 253a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @see PlaybackGlueHost#isControlsOverlayAutoHideEnabled() 254a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 255a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public boolean isControlsOverlayAutoHideEnabled() { 256a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mFadeWhenPlaying; 257a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 258a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 259a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 260a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Sets the controls row to be managed by the glue layer. If 261a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link PlaybackControlsRow#getPrimaryActionsAdapter()} is not provided, a default 262a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link ArrayObjectAdapter} will be created and initialized in 263a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link #onCreatePrimaryActions(ArrayObjectAdapter)}. If 264a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link PlaybackControlsRow#getSecondaryActionsAdapter()} is not provided, a default 265a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link ArrayObjectAdapter} will be created and initialized in 266a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link #onCreateSecondaryActions(ArrayObjectAdapter)}. 267a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * The primary actions and playback state related aspects of the row 268a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * are updated by the glue. 269a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 270a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void setControlsRow(PlaybackControlsRow controlsRow) { 271a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow = controlsRow; 272a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setCurrentPosition(-1); 273a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setDuration(-1); 274a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setBufferedPosition(-1); 275a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRow.getPrimaryActionsAdapter() == null) { 276a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin ArrayObjectAdapter adapter = new ArrayObjectAdapter( 277a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin new ControlButtonPresenterSelector()); 278a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onCreatePrimaryActions(adapter); 279a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setPrimaryActionsAdapter(adapter); 280a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 281a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin // Add secondary actions 282a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRow.getSecondaryActionsAdapter() == null) { 283a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin ArrayObjectAdapter secondaryActions = new ArrayObjectAdapter( 284a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin new ControlButtonPresenterSelector()); 285a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onCreateSecondaryActions(secondaryActions); 286a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin getControlsRow().setSecondaryActionsAdapter(secondaryActions); 287a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 288a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin updateControlsRow(); 289a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 290a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 291a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 292a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Sets the controls row Presenter to be managed by the glue layer. 293a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 294a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void setPlaybackRowPresenter(PlaybackRowPresenter presenter) { 295a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRowPresenter = presenter; 296a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 297a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 298a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 299a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Returns the playback controls row managed by the glue layer. 300a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 301a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public PlaybackControlsRow getControlsRow() { 302a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mControlsRow; 303a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 304a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 305a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 306a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Returns the playback controls row Presenter managed by the glue layer. 307a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 308a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public PlaybackRowPresenter getPlaybackRowPresenter() { 309a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mControlsRowPresenter; 310a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 311a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 312a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 313a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Handles action clicks. A subclass may override this add support for additional actions. 314a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 315a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 316a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public abstract void onActionClicked(Action action); 317a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 318a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 319a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Handles key events and returns true if handled. A subclass may override this to provide 320a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * additional support. 321a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 322a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 323a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public abstract boolean onKey(View v, int keyCode, KeyEvent event); 324a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 325a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin private void updateControlsRow() { 326a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onMetadataChanged(); 327a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 328a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 329a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 330a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public final boolean isPlaying() { 331a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mPlayerAdapter.isPlaying(); 332a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 333a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 334a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 335a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void play() { 336a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.play(); 337a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 338a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 339a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 340a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void pause() { 341a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.pause(); 342a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 343a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 344a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected static void notifyItemChanged(ArrayObjectAdapter adapter, Object object) { 345a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin int index = adapter.indexOf(object); 346a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (index >= 0) { 347a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin adapter.notifyArrayItemRangeChanged(index, 1); 348a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 349a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 350a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 351a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 352a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * May be overridden to add primary actions to the adapter. Default implementation add 353a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link PlaybackControlsRow.PlayPauseAction}. 354a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 355a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param primaryActionsAdapter The adapter to add primary {@link Action}s. 356a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 357a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onCreatePrimaryActions(ArrayObjectAdapter primaryActionsAdapter) { 358a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 359a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 360a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 361a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * May be overridden to add secondary actions to the adapter. 362a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * 363a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param secondaryActionsAdapter The adapter you need to add the {@link Action}s to. 364a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 365a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onCreateSecondaryActions(ArrayObjectAdapter secondaryActionsAdapter) { 366a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 367a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 368a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onUpdateProgress() { 369a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRow != null) { 370a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setCurrentPosition(mPlayerAdapter.isPrepared() 371a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin ? getCurrentPosition() : -1); 372a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 373a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 374a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 375a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onUpdateBufferedProgress() { 376a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRow != null) { 377a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setBufferedPosition(mPlayerAdapter.getBufferedPosition()); 378a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 379a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 380a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 381a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onUpdateDuration() { 382a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRow != null) { 383a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setDuration( 384a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.isPrepared() ? mPlayerAdapter.getDuration() : -1); 385a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 386a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 387a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 388a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 389a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @return The duration of the media item in milliseconds. 390a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 391a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public final long getDuration() { 392a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mPlayerAdapter.getDuration(); 393a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 394a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 395a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 396a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @return The current position of the media item in milliseconds. 397a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 398a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public long getCurrentPosition() { 399a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mPlayerAdapter.getCurrentPosition(); 400a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 401a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 402a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 403a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @return The current buffered position of the media item in milliseconds. 404a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 405a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public final long getBufferedPosition() { 406a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mPlayerAdapter.getBufferedPosition(); 407a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 408a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 409a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @Override 410a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public final boolean isPrepared() { 411a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mPlayerAdapter.isPrepared(); 412a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 413a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 414a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 415a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Event when ready state for play changes. 416a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 417a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @CallSuper 418a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onPreparedStateChanged() { 419a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin onUpdateDuration(); 420a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin List<PlayerCallback> callbacks = getPlayerCallbacks(); 421a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (callbacks != null) { 422a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin for (int i = 0, size = callbacks.size(); i < size; i++) { 423a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin callbacks.get(i).onPreparedStateChanged(this); 424a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 425a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 426a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 427a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 428a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 429a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Sets the drawable representing cover image. The drawable will be rendered by default 430a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * description presenter in 431a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link PlaybackTransportRowPresenter#setDescriptionPresenter(Presenter)}. 432a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param cover The drawable representing cover image. 433a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 434a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void setArt(Drawable cover) { 435a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mCover == cover) { 436a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return; 437a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 438a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin this.mCover = cover; 439a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setImageDrawable(mCover); 440a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (getHost() != null) { 441a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin getHost().notifyPlaybackRowChanged(); 442a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 443a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 444a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 445a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 446a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @return The drawable representing cover image. 447a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 448a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public Drawable getArt() { 449a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mCover; 450a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 451a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 452a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 453a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Sets the media subtitle. The subtitle will be rendered by default description presenter 454a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link PlaybackTransportRowPresenter#setDescriptionPresenter(Presenter)}. 455a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param subtitle Subtitle to set. 456a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 457a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void setSubtitle(CharSequence subtitle) { 458a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (TextUtils.equals(subtitle, mSubtitle)) { 459a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return; 460a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 461a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mSubtitle = subtitle; 462a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (getHost() != null) { 463a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin getHost().notifyPlaybackRowChanged(); 464a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 465a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 466a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 467a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 468a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Return The media subtitle. 469a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 470a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public CharSequence getSubtitle() { 471a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mSubtitle; 472a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 473a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 474a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 475a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Sets the media title. The title will be rendered by default description presenter 476a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * {@link PlaybackTransportRowPresenter#setDescriptionPresenter(Presenter)}. 477a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 478a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public void setTitle(CharSequence title) { 479a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (TextUtils.equals(title, mTitle)) { 480a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return; 481a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 482a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mTitle = title; 483a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (getHost() != null) { 484a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin getHost().notifyPlaybackRowChanged(); 485a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 486a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 487a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 488a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 489a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Returns the title of the media item. 490a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 491a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public CharSequence getTitle() { 492a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return mTitle; 493a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 494a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 495a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 496a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Event when metadata changed 497a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 498a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin void onMetadataChanged() { 499a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (mControlsRow == null) { 500a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin return; 501a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 502a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 503a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (DEBUG) Log.v(TAG, "updateRowMetadata"); 504a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 505a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setImageDrawable(getArt()); 506a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setDuration(mPlayerAdapter.getDuration()); 507a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mControlsRow.setCurrentPosition(getCurrentPosition()); 508a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 509a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (getHost() != null) { 510a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin getHost().notifyPlaybackRowChanged(); 511a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 512a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 513a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 514a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 515a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Event when play state changed. 516a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 517a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @CallSuper 518a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onPlayStateChanged() { 519a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin List<PlayerCallback> callbacks = getPlayerCallbacks(); 520a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (callbacks != null) { 521a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin for (int i = 0, size = callbacks.size(); i < size; i++) { 522a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin callbacks.get(i).onPlayStateChanged(this); 523a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 524a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 525a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 526a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 527a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 528a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Event when play finishes, subclass may handling repeat mode here. 529a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 530a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin @CallSuper 531a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin protected void onPlayCompleted() { 532a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin List<PlayerCallback> callbacks = getPlayerCallbacks(); 533a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin if (callbacks != null) { 534a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin for (int i = 0, size = callbacks.size(); i < size; i++) { 535a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin callbacks.get(i).onPlayCompleted(this); 536a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 537a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 538a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 539a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 540a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin /** 541a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * Seek media to a new position. 542a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin * @param position New position. 543a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin */ 544a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin public final void seekTo(long position) { 545a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin mPlayerAdapter.seekTo(position); 546a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin } 547a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin 548a4952dd9e1ddd678743f49d9d728b9b8c5fc7232Wei-Hsin} 549