1eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutpackage android.support.v17.leanback.app; 2eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 3eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.content.Context; 4eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.graphics.drawable.Drawable; 5eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.os.Handler; 6eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.os.Message; 7eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter; 8eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.Action; 9eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.ControlButtonPresenterSelector; 1060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stoutimport android.support.v17.leanback.widget.OnActionClickedListener; 11eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.OnItemViewClickedListener; 12eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.PlaybackControlsRow; 13eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.PlaybackControlsRowPresenter; 14eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.Presenter; 15eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.PresenterSelector; 16eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.Row; 17eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.RowPresenter; 18eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.support.v17.leanback.widget.SparseArrayObjectAdapter; 19eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.util.Log; 20eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.view.InputEvent; 21eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stoutimport android.view.KeyEvent; 2260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stoutimport android.view.View; 23eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 24eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 25eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout/** 26eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow} and 27eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * {@link PlaybackOverlayFragment} that implements a recommended approach to handling standard 28eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * playback control actions such as play/pause, fast forward/rewind at progressive speed levels, 29eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * and skip to next/previous. This helper class is a glue layer in that it manages the 30eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * configuration of and interaction between the leanback UI components by defining a functional 31eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * interface to the media player. 32eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 33eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * <p>You can instantiate a concrete subclass such as {@link MediaControllerGlue} or you must 34eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * subclass this abstract helper. To create a subclass you must implement all of the 35eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * abstract methods and the subclass must invoke {@link #onMetadataChanged()} and 36eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * {@link #onStateChanged()} appropriately. 37eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * </p> 38eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 39eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * <p>To use an instance of the glue layer, first construct an instance. Constructor parameters 4060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * inform the glue what speed levels are supported for fast forward/rewind. Providing a 4160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * {@link android.support.v17.leanback.app.PlaybackOverlayFragment} is optional. 4260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * </p> 4360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * 4460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * <p>If you have your own controls row you must pass it to {@link #setControlsRow}. 4560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * The row will be updated by the glue layer based on the media metadata and playback state. 4660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * Alternatively, you may call {@link #createControlsRowAndPresenter()} which will set a controls 4760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * row and return a row presenter you can use to present the row. 48eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * </p> 49eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 50eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * <p>The helper sets a {@link android.support.v17.leanback.widget.SparseArrayObjectAdapter} 51eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * on the controls row as the primary actions adapter, and adds actions to it. You can provide 52eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * additional actions by overriding {@link #createPrimaryActionsAdapter}. This helper does not 53eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * deal in secondary actions so those you may add separately. 54eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * </p> 55eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 5660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * <p>Provide a click listener on your fragment and if an action is clicked, call 5760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * {@link #onActionClicked}. There is no need to call {@link #setOnItemViewClickedListener} 5860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * but if you do a click listener will be installed on the fragment and recognized action clicks 5960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * will be handled. Your listener will be called only for unhandled actions. 6060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * </p> 6160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * 6260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * <p>The helper implements a key event handler. If you pass a 6360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * {@link android.support.v17.leanback.app.PlaybackOverlayFragment} the fragment's input event 6460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * handler will be set. Otherwise, you should set the glue object as key event handler to the 6560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * ViewHolder when bound by your row presenter; see 6660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}. 67eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * </p> 68eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 69eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * <p>To update the controls row progress during playback, override {@link #enableProgressUpdating} 70eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * to manage the lifecycle of a periodic callback to {@link #updateProgress()}. 71eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * {@link #getUpdatePeriod()} provides a recommended update period. 72eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * </p> 73eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 74eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 7560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stoutpublic abstract class PlaybackControlGlue implements OnActionClickedListener, View.OnKeyListener { 76eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 77ce4c2014042fe6e4723bab30741039848adcf4beDake Gu * The adapter key for the first custom control on the left side 78eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * of the predefined primary controls. 79eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 80eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int ACTION_CUSTOM_LEFT_FIRST = 0x1; 81eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 82eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 83eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The adapter key for the skip to previous control. 84eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 85eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int ACTION_SKIP_TO_PREVIOUS = 0x10; 86eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 87eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 88eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The adapter key for the rewind control. 89eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 90eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int ACTION_REWIND = 0x20; 91eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 92eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 93eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The adapter key for the play/pause control. 94eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 95eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int ACTION_PLAY_PAUSE = 0x40; 96eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 97eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 98eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The adapter key for the fast forward control. 99eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 100eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int ACTION_FAST_FORWARD = 0x80; 101eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 102eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 103eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The adapter key for the skip to next control. 104eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 105eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int ACTION_SKIP_TO_NEXT = 0x100; 106eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 107eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 108eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The adapter key for the first custom control on the right side 109eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * of the predefined primary controls. 110eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 111eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int ACTION_CUSTOM_RIGHT_FIRST = 0x1000; 112eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 113eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 114eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Invalid playback speed. 115eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 116eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_INVALID = -1; 117eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 118eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 119eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Speed representing playback state that is paused. 120eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 121eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_PAUSED = 0; 122eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 123eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 124eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Speed representing playback state that is playing normally. 125eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 126eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_NORMAL = 1; 127eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 128eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 129eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The initial (level 0) fast forward playback speed. 130eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The negative of this value is for rewind at the same speed. 131eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 132eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_FAST_L0 = 10; 133eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 134eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 135eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The level 1 fast forward playback speed. 136eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The negative of this value is for rewind at the same speed. 137eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 138eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_FAST_L1 = 11; 139eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 140eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 141eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The level 2 fast forward playback speed. 142eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The negative of this value is for rewind at the same speed. 143eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 144eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_FAST_L2 = 12; 145eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 146eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 147eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The level 3 fast forward playback speed. 148eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The negative of this value is for rewind at the same speed. 149eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 150eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_FAST_L3 = 13; 151eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 152eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 153eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The level 4 fast forward playback speed. 154eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The negative of this value is for rewind at the same speed. 155eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 156eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public static final int PLAYBACK_SPEED_FAST_L4 = 14; 157eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 158eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private static final String TAG = "PlaybackControlGlue"; 159eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private static final boolean DEBUG = false; 160eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 161eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private static final int MSG_UPDATE_PLAYBACK_STATE = 100; 162eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private static final int UPDATE_PLAYBACK_STATE_DELAY_MS = 2000; 163eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private static final int NUMBER_OF_SEEK_SPEEDS = PLAYBACK_SPEED_FAST_L4 - 164eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PLAYBACK_SPEED_FAST_L0 + 1; 165eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 166eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private final PlaybackOverlayFragment mFragment; 167eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private final Context mContext; 168eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private final int[] mFastForwardSpeeds; 169eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private final int[] mRewindSpeeds; 170eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private PlaybackControlsRow mControlsRow; 171eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private SparseArrayObjectAdapter mPrimaryActionsAdapter; 172eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private PlaybackControlsRow.PlayPauseAction mPlayPauseAction; 173eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private PlaybackControlsRow.SkipNextAction mSkipNextAction; 174eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction; 175eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private PlaybackControlsRow.FastForwardAction mFastForwardAction; 176eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private PlaybackControlsRow.RewindAction mRewindAction; 177eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private OnItemViewClickedListener mExternalOnItemViewClickedListener; 178eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private int mPlaybackSpeed = PLAYBACK_SPEED_NORMAL; 179f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout private boolean mFadeWhenPlaying = true; 180eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 181eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private final Handler mHandler = new Handler() { 182eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout @Override 183eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public void handleMessage(Message msg) { 184eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (msg.what == MSG_UPDATE_PLAYBACK_STATE) { 185eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackState(); 186eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 187eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 188eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout }; 189eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 190eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private final OnItemViewClickedListener mOnItemViewClickedListener = 191eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout new OnItemViewClickedListener() { 192eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout @Override 193eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public void onItemClicked(Presenter.ViewHolder viewHolder, Object object, 194eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout RowPresenter.ViewHolder viewHolder2, Row row) { 195eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (DEBUG) Log.v(TAG, "onItemClicked " + object); 196eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout boolean handled = false; 197eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (object instanceof Action) { 19860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout handled = dispatchAction((Action) object, null); 199eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 200eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (!handled && mExternalOnItemViewClickedListener != null) { 201eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mExternalOnItemViewClickedListener.onItemClicked(viewHolder, object, 202eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout viewHolder2, row); 203eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 204eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 205eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout }; 206eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 20760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout /** 20860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * Constructor for the glue. 20960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * 21060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @param context 21160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @param seekSpeeds Array of seek speeds for fast forward and rewind. 21260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout */ 21360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout public PlaybackControlGlue(Context context, int[] seekSpeeds) { 21460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout this(context, null, seekSpeeds, seekSpeeds); 21560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 216eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 217eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 218eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Constructor for the glue. 219eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 22060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @param context 22160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @param fastForwardSpeeds Array of seek speeds for fast forward. 22260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @param rewindSpeeds Array of seek speeds for rewind. 22360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout */ 22460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout public PlaybackControlGlue(Context context, 22560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout int[] fastForwardSpeeds, 22660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout int[] rewindSpeeds) { 22760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout this(context, null, fastForwardSpeeds, rewindSpeeds); 22860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 22960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout 23060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout /** 23160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * Constructor for the glue. 232eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 233eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * @param context 23460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in. 235eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * @param seekSpeeds Array of seek speeds for fast forward and rewind. 236eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 237eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public PlaybackControlGlue(Context context, 238eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PlaybackOverlayFragment fragment, 239eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int[] seekSpeeds) { 240eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout this(context, fragment, seekSpeeds, seekSpeeds); 241eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 242eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 243eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 244eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Constructor for the glue. 245eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * 246eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * @param context 24760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in. 248eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * @param fastForwardSpeeds Array of seek speeds for fast forward. 249eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * @param rewindSpeeds Array of seek speeds for rewind. 250eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 251eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public PlaybackControlGlue(Context context, 252eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PlaybackOverlayFragment fragment, 253eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int[] fastForwardSpeeds, 254eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int[] rewindSpeeds) { 255eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mContext = context; 256eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mFragment = fragment; 25760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (fragment != null) { 25860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout attachToFragment(); 259eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 260eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (fastForwardSpeeds.length == 0 || fastForwardSpeeds.length > NUMBER_OF_SEEK_SPEEDS) { 261eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout throw new IllegalStateException("invalid fastForwardSpeeds array size"); 262eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 263eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mFastForwardSpeeds = fastForwardSpeeds; 264eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (rewindSpeeds.length == 0 || rewindSpeeds.length > NUMBER_OF_SEEK_SPEEDS) { 265eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout throw new IllegalStateException("invalid rewindSpeeds array size"); 266eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 267eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mRewindSpeeds = rewindSpeeds; 268eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 269eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 27060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout private final PlaybackOverlayFragment.InputEventHandler mOnInputEventHandler = 27160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout new PlaybackOverlayFragment.InputEventHandler() { 27260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout @Override 27360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout public boolean handleInputEvent(InputEvent event) { 27460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (event instanceof KeyEvent) { 27560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout KeyEvent keyEvent = (KeyEvent) event; 27660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout return onKey(null, keyEvent.getKeyCode(), keyEvent); 27760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 27860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout return false; 27960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 28060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout }; 28160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout 28260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout private void attachToFragment() { 28360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout mFragment.setInputEventHandler(mOnInputEventHandler); 28460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 28560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout 286eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 287eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Helper method for instantiating a 288eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * {@link android.support.v17.leanback.widget.PlaybackControlsRow} and corresponding 289eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * {@link android.support.v17.leanback.widget.PlaybackControlsRowPresenter}. 290eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 291eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public PlaybackControlsRowPresenter createControlsRowAndPresenter() { 292eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PlaybackControlsRow controlsRow = new PlaybackControlsRow(this); 293eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout setControlsRow(controlsRow); 294eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 29560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout AbstractDetailsDescriptionPresenter detailsPresenter = 29660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout new AbstractDetailsDescriptionPresenter() { 297eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout @Override 298eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected void onBindDescription(AbstractDetailsDescriptionPresenter.ViewHolder 299eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout viewHolder, Object object) { 300eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PlaybackControlGlue glue = (PlaybackControlGlue) object; 301eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (glue.hasValidMedia()) { 302eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout viewHolder.getTitle().setText(glue.getMediaTitle()); 303eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout viewHolder.getSubtitle().setText(glue.getMediaSubtitle()); 304eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 305eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout viewHolder.getTitle().setText(""); 306eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout viewHolder.getSubtitle().setText(""); 307eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 308eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 30960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout }; 31060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout return new PlaybackControlsRowPresenter(detailsPresenter) { 31160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout @Override 31260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) { 31360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout super.onBindRowViewHolder(vh, item); 31460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout vh.setOnKeyListener(PlaybackControlGlue.this); 31560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 31660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout @Override 31760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout protected void onUnbindRowViewHolder(RowPresenter.ViewHolder vh) { 31860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout super.onUnbindRowViewHolder(vh); 31960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout vh.setOnKeyListener(null); 32060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 32160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout }; 322eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 323eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 324eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 325eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the fragment. 326eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 327eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public PlaybackOverlayFragment getFragment() { 328eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return mFragment; 329eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 330eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 331eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 332eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the context. 333eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 334eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public Context getContext() { 335eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return mContext; 336eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 337eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 338eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 339eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the fast forward speeds. 340eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 341eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public int[] getFastForwardSpeeds() { 342eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return mFastForwardSpeeds; 343eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 344eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 345eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 346eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the rewind speeds. 347eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 348eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public int[] getRewindSpeeds() { 349eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return mRewindSpeeds; 350eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 351eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 352eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 353c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout * Sets the controls to fade after a timeout when media is playing. 354c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout */ 355c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout public void setFadingEnabled(boolean enable) { 356c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout mFadeWhenPlaying = enable; 35760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (!mFadeWhenPlaying && mFragment != null) { 358c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout mFragment.setFadingEnabled(false); 359c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout } 360c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout } 361c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout 362c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout /** 363c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout * Returns true if controls are set to fade when media is playing. 364c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout */ 365c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout public boolean isFadingEnabled() { 366c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout return mFadeWhenPlaying; 367c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout } 368c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout 369c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout /** 370eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Set the {@link OnItemViewClickedListener} to be called if the click event 371eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * is not handled internally. 372eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * @param listener 37360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * @deprecated Don't call this. Instead set the listener on the fragment yourself, 37460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * and call {@link #onActionClicked} to handle clicks. 375eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 376d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette @Deprecated 377eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public void setOnItemViewClickedListener(OnItemViewClickedListener listener) { 378eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mExternalOnItemViewClickedListener = listener; 37960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (mFragment != null) { 38060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout mFragment.setOnItemViewClickedListener(mOnItemViewClickedListener); 38160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 382eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 383eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 384eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 385eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the {@link OnItemViewClickedListener}. 386eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 387eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public OnItemViewClickedListener getOnItemViewClickedListener() { 388eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return mExternalOnItemViewClickedListener; 389eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 390eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 391eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 392eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Sets the controls row to be managed by the glue layer. 393eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * The primary actions and playback state related aspects of the row 394eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * are updated by the glue. 395eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 396eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public void setControlsRow(PlaybackControlsRow controlsRow) { 397eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow = controlsRow; 398eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter = createPrimaryActionsAdapter( 399eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout new ControlButtonPresenterSelector()); 400eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter); 401eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updateControlsRow(); 402eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 403eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 404eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 405eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the playback controls row managed by the glue layer. 406eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 407eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public PlaybackControlsRow getControlsRow() { 408eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return mControlsRow; 409eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 410eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 411eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 412eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Override this to start/stop a runnable to call {@link #updateProgress} at 413eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * an interval such as {@link #getUpdatePeriod}. 414eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 415eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public void enableProgressUpdating(boolean enable) { 416eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 417eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 418eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 419eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the time period in milliseconds that should be used 420eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * to update the progress. See {@link #updateProgress()}. 421eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 422eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public int getUpdatePeriod() { 423eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout // TODO: calculate a better update period based on total duration and screen size 424eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return 500; 425eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 426eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 427eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 428eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Updates the progress bar based on the current media playback position. 429eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 430eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public void updateProgress() { 431eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int position = getCurrentPosition(); 432eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (DEBUG) Log.v(TAG, "updateProgress " + position); 433eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setCurrentTime(position); 434eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 435eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 43660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout /** 43760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * Handles action clicks. A subclass may override this add support for additional actions. 43860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout */ 43960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout @Override 44060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout public void onActionClicked(Action action) { 44160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout dispatchAction(action, null); 44260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 44360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout 44460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout /** 44560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * Handles key events and returns true if handled. A subclass may override this to provide 44660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * additional support. 44760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout */ 44860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout @Override 44960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout public boolean onKey(View v, int keyCode, KeyEvent event) { 45060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout switch (keyCode) { 45160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout case KeyEvent.KEYCODE_DPAD_UP: 45260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout case KeyEvent.KEYCODE_DPAD_DOWN: 45360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout case KeyEvent.KEYCODE_DPAD_RIGHT: 45460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout case KeyEvent.KEYCODE_DPAD_LEFT: 45560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout case KeyEvent.KEYCODE_BACK: 456c89266e21f0269aecd5df2dc2a39f6f0cf11a58eCraig Stout case KeyEvent.KEYCODE_ESCAPE: 45760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout boolean abortSeek = mPlaybackSpeed >= PLAYBACK_SPEED_FAST_L0 || 45860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout mPlaybackSpeed <= -PLAYBACK_SPEED_FAST_L0; 45960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (abortSeek) { 46060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout mPlaybackSpeed = PLAYBACK_SPEED_NORMAL; 46160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout startPlayback(mPlaybackSpeed); 46260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout updatePlaybackStatusAfterUserAction(); 463c89266e21f0269aecd5df2dc2a39f6f0cf11a58eCraig Stout return keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE; 46460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 46560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout return false; 46660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 46760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout Action action = mControlsRow.getActionForKeyCode(mPrimaryActionsAdapter, keyCode); 46860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (action != null) { 46960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (action == mPrimaryActionsAdapter.lookup(ACTION_PLAY_PAUSE) || 47060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout action == mPrimaryActionsAdapter.lookup(ACTION_REWIND) || 47160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout action == mPrimaryActionsAdapter.lookup(ACTION_FAST_FORWARD) || 47260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_PREVIOUS) || 47360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_NEXT)) { 47460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (((KeyEvent) event).getAction() == KeyEvent.ACTION_DOWN) { 47560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout dispatchAction(action, (KeyEvent) event); 47660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 47760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout return true; 47860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 47960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 48060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout return false; 48160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 48260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout 48360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout /** 48460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout * Called when the given action is invoked, either by click or keyevent. 48560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout */ 48660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout private boolean dispatchAction(Action action, KeyEvent keyEvent) { 487eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout boolean handled = false; 488eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (action == mPlayPauseAction) { 48960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout boolean canPlay = keyEvent == null || 49060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || 49160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY; 49260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout boolean canPause = keyEvent == null || 49360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || 49460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE; 495eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mPlaybackSpeed != PLAYBACK_SPEED_NORMAL) { 49660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (canPlay) { 49760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout mPlaybackSpeed = PLAYBACK_SPEED_NORMAL; 49860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout startPlayback(mPlaybackSpeed); 49960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } 50060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout } else if (canPause) { 501eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPlaybackSpeed = PLAYBACK_SPEED_PAUSED; 502eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout pausePlayback(); 503eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 504eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackStatusAfterUserAction(); 505eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout handled = true; 506eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else if (action == mSkipNextAction) { 507eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout skipToNext(); 508eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout handled = true; 509eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else if (action == mSkipPreviousAction) { 510eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout skipToPrevious(); 511eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout handled = true; 512eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else if (action == mFastForwardAction) { 513eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mPlaybackSpeed < getMaxForwardSpeedId()) { 514eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout switch (mPlaybackSpeed) { 515eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L0: 516eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L1: 517eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L2: 518eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L3: 519eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPlaybackSpeed++; 520eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout break; 52160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout default: 52260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout mPlaybackSpeed = PLAYBACK_SPEED_FAST_L0; 52360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout break; 524eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 525eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout startPlayback(mPlaybackSpeed); 526eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackStatusAfterUserAction(); 527eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 528eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout handled = true; 529eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else if (action == mRewindAction) { 530eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mPlaybackSpeed > -getMaxRewindSpeedId()) { 531eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout switch (mPlaybackSpeed) { 532eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L0: 533eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L1: 534eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L2: 535eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L3: 536eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPlaybackSpeed--; 537eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout break; 53860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout default: 53960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout mPlaybackSpeed = -PLAYBACK_SPEED_FAST_L0; 54060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout break; 541eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 542eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout startPlayback(mPlaybackSpeed); 543eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackStatusAfterUserAction(); 544eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 545eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout handled = true; 546eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 547eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return handled; 548eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 549eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 550eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private int getMaxForwardSpeedId() { 551eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return PLAYBACK_SPEED_FAST_L0 + (mFastForwardSpeeds.length - 1); 552eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 553eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 554eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private int getMaxRewindSpeedId() { 555eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return PLAYBACK_SPEED_FAST_L0 + (mRewindSpeeds.length - 1); 556eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 557eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 558eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private void updateControlsRow() { 559eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updateRowMetadata(); 560eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE); 561eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackState(); 562eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 563eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 564eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private void updatePlaybackStatusAfterUserAction() { 565eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackState(mPlaybackSpeed); 566eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout // Sync playback state after a delay 567eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE); 568eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE, 569eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout UPDATE_PLAYBACK_STATE_DELAY_MS); 570eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 571eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 572eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private void updateRowMetadata() { 573eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mControlsRow == null) { 574eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return; 575eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 576eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 577eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (DEBUG) Log.v(TAG, "updateRowMetadata hasValidMedia " + hasValidMedia()); 578eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 579eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (!hasValidMedia()) { 580eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setImageDrawable(null); 581eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setTotalTime(0); 582eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setCurrentTime(0); 583eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 584eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setImageDrawable(getMediaArt()); 585eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setTotalTime(getMediaDuration()); 586eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mControlsRow.setCurrentTime(getCurrentPosition()); 587eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 588eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 589eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout onRowChanged(mControlsRow); 590eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 591eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 592eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private void updatePlaybackState() { 593eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (hasValidMedia()) { 594eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPlaybackSpeed = getCurrentSpeedId(); 595eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackState(mPlaybackSpeed); 596eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 597eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 598eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 599eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private void updatePlaybackState(int playbackSpeed) { 600eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mControlsRow == null) { 601eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return; 602eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 603eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 604eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout final long actions = getSupportedActions(); 605eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0) { 606eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mSkipPreviousAction == null) { 607eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(mContext); 608eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 609eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.set(ACTION_SKIP_TO_PREVIOUS, mSkipPreviousAction); 610eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 611eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_PREVIOUS); 612eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mSkipPreviousAction = null; 613eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 614eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if ((actions & ACTION_REWIND) != 0) { 615eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mRewindAction == null) { 616eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mRewindAction = new PlaybackControlsRow.RewindAction(mContext, 617eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mRewindSpeeds.length); 618eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 619eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.set(ACTION_REWIND, mRewindAction); 620eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 621eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.clear(ACTION_REWIND); 622eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mRewindAction = null; 623eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 624eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if ((actions & ACTION_PLAY_PAUSE) != 0) { 625eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mPlayPauseAction == null) { 626eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(mContext); 627eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 628eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.set(ACTION_PLAY_PAUSE, mPlayPauseAction); 629eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 630eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.clear(ACTION_PLAY_PAUSE); 631eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPlayPauseAction = null; 632eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 633eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if ((actions & ACTION_FAST_FORWARD) != 0) { 634eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mFastForwardAction == null) { 635eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mFastForwardAction = new PlaybackControlsRow.FastForwardAction(mContext, 636eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mFastForwardSpeeds.length); 637eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 638eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.set(ACTION_FAST_FORWARD, mFastForwardAction); 639eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 640eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.clear(ACTION_FAST_FORWARD); 641eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mFastForwardAction = null; 642eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 643eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if ((actions & ACTION_SKIP_TO_NEXT) != 0) { 644eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mSkipNextAction == null) { 645eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mSkipNextAction = new PlaybackControlsRow.SkipNextAction(mContext); 646eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 647eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.set(ACTION_SKIP_TO_NEXT, mSkipNextAction); 648eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 649eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_NEXT); 650eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mSkipNextAction = null; 651eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 652eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 653eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mFastForwardAction != null) { 654eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int index = 0; 655eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (playbackSpeed >= PLAYBACK_SPEED_FAST_L0) { 656eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout index = playbackSpeed - PLAYBACK_SPEED_FAST_L0; 657eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (playbackSpeed < getMaxForwardSpeedId()) { 658eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout index++; 659eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 660eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 661eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mFastForwardAction.getIndex() != index) { 662eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mFastForwardAction.setIndex(index); 663eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout notifyItemChanged(mPrimaryActionsAdapter, mFastForwardAction); 664eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 665eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 666eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mRewindAction != null) { 667eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int index = 0; 668eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (playbackSpeed <= -PLAYBACK_SPEED_FAST_L0) { 669eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout index = -playbackSpeed - PLAYBACK_SPEED_FAST_L0; 670eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (-playbackSpeed < getMaxRewindSpeedId()) { 671eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout index++; 672eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 673eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 674eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mRewindAction.getIndex() != index) { 675eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mRewindAction.setIndex(index); 676eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout notifyItemChanged(mPrimaryActionsAdapter, mRewindAction); 677eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 678eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 679eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 680eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (playbackSpeed == PLAYBACK_SPEED_PAUSED) { 681eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updateProgress(); 682eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout enableProgressUpdating(false); 683eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 684eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout enableProgressUpdating(true); 685eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 686eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 68760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout if (mFadeWhenPlaying && mFragment != null) { 688eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mFragment.setFadingEnabled(playbackSpeed == PLAYBACK_SPEED_NORMAL); 689eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 690eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 691eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mPlayPauseAction != null) { 692eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int index = playbackSpeed == PLAYBACK_SPEED_PAUSED ? 693eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PlaybackControlsRow.PlayPauseAction.PLAY : 694eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PlaybackControlsRow.PlayPauseAction.PAUSE; 695eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mPlayPauseAction.getIndex() != index) { 696eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mPlayPauseAction.setIndex(index); 697eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout notifyItemChanged(mPrimaryActionsAdapter, mPlayPauseAction); 698eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 699eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 700eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 701eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 702eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private static void notifyItemChanged(SparseArrayObjectAdapter adapter, Object object) { 703eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout int index = adapter.indexOf(object); 704eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (index >= 0) { 705eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout adapter.notifyArrayItemRangeChanged(index, 1); 706eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 707eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 708eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 709eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout private static String getSpeedString(int speed) { 710eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout switch (speed) { 711eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_INVALID: 712eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_INVALID"; 713eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_PAUSED: 714eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_PAUSED"; 715eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_NORMAL: 716eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_NORMAL"; 717eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L0: 718eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_FAST_L0"; 719eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L1: 720eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_FAST_L1"; 721eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L2: 722eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_FAST_L2"; 723eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L3: 724eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_FAST_L3"; 725eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case PLAYBACK_SPEED_FAST_L4: 726eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "PLAYBACK_SPEED_FAST_L4"; 727eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L0: 728eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "-PLAYBACK_SPEED_FAST_L0"; 729eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L1: 730eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "-PLAYBACK_SPEED_FAST_L1"; 731eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L2: 732eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "-PLAYBACK_SPEED_FAST_L2"; 733eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L3: 734eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "-PLAYBACK_SPEED_FAST_L3"; 735eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout case -PLAYBACK_SPEED_FAST_L4: 736eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return "-PLAYBACK_SPEED_FAST_L4"; 737eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 738eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return null; 739eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 740eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 741eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 742eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns true if there is a valid media item. 743eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 744eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract boolean hasValidMedia(); 745eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 746eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 747eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns true if media is currently playing. 748eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 749eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract boolean isMediaPlaying(); 750eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 751eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 752eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the title of the media item. 753eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 754eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract CharSequence getMediaTitle(); 755eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 756eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 757eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the subtitle of the media item. 758eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 759eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract CharSequence getMediaSubtitle(); 760eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 761eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 762eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the duration of the media item in milliseconds. 763eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 764eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract int getMediaDuration(); 765eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 766eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 767eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns a bitmap of the art for the media item. 768eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 769eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract Drawable getMediaArt(); 770eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 771eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 772eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns a bitmask of actions supported by the media player. 773eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 774eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract long getSupportedActions(); 775eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 776eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 777eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the current playback speed. When playing normally, 778eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * {@link #PLAYBACK_SPEED_NORMAL} should be returned. 779eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 780eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract int getCurrentSpeedId(); 781eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 782eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 783eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Returns the current position of the media item in milliseconds. 784eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 785eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout public abstract int getCurrentPosition(); 786eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 787eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 788eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Start playback at the given speed. 789eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * @param speed The desired playback speed. For normal playback this will be 790eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * {@link #PLAYBACK_SPEED_NORMAL}; higher positive values for fast forward, 791eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * and negative values for rewind. 792eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 793eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected abstract void startPlayback(int speed); 794eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 795eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 796eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Pause playback. 797eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 798eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected abstract void pausePlayback(); 799eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 800eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 801eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Skip to the next track. 802eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 803eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected abstract void skipToNext(); 804eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 805eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 806eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Skip to the previous track. 807eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 808eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected abstract void skipToPrevious(); 809eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 810eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 811eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Invoked when the playback controls row has changed. The adapter containing this row 812eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * should be notified. 813eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 814eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected abstract void onRowChanged(PlaybackControlsRow row); 815eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 816eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 817eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Creates the primary action adapter. May be overridden to add additional primary 818eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * actions to the adapter. 819eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 820eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected SparseArrayObjectAdapter createPrimaryActionsAdapter( 821eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout PresenterSelector presenterSelector) { 822eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return new SparseArrayObjectAdapter(presenterSelector); 823eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 824eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 825eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 826eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Must be called appropriately by a subclass when the playback state has changed. 827eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 828eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected void onStateChanged() { 829eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (DEBUG) Log.v(TAG, "onStateChanged"); 830eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout // If a pending control button update is present, delay 831eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout // the update until the state settles. 832eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (!hasValidMedia()) { 833eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout return; 834eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 835eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (mHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE)) { 836eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE); 837eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (getCurrentSpeedId() != mPlaybackSpeed) { 838eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (DEBUG) Log.v(TAG, "Status expectation mismatch, delaying update"); 839eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE, 840eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout UPDATE_PLAYBACK_STATE_DELAY_MS); 841eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 842eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (DEBUG) Log.v(TAG, "Update state matches expectation"); 843eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackState(); 844eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 845eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } else { 846eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updatePlaybackState(); 847eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 848eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 849eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout 850eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout /** 851eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout * Must be called appropriately by a subclass when the metadata state has changed. 852eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout */ 853eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout protected void onMetadataChanged() { 854eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout if (DEBUG) Log.v(TAG, "onMetadataChanged"); 855eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout updateRowMetadata(); 856eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout } 857eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout} 858