1 /* This file is auto-generated from PlaybackControlHelper.java. DO NOT MODIFY. */ 2 3 /* 4 * Copyright (C) 2015 The Android Open Source Project 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License 17 */ 18 19 package com.example.android.leanback; 20 21 import android.content.Context; 22 import android.graphics.drawable.Drawable; 23 import android.os.Handler; 24 import android.support.v17.leanback.app.PlaybackControlSupportGlue; 25 import android.support.v17.leanback.widget.Action; 26 import android.support.v17.leanback.widget.ArrayObjectAdapter; 27 import android.support.v17.leanback.widget.ControlButtonPresenterSelector; 28 import android.support.v17.leanback.widget.PlaybackControlsRow; 29 import android.support.v17.leanback.widget.PlaybackControlsRowPresenter; 30 import android.support.v17.leanback.widget.PresenterSelector; 31 import android.support.v17.leanback.widget.SparseArrayObjectAdapter; 32 import android.view.KeyEvent; 33 import android.view.View; 34 import android.widget.Toast; 35 36 abstract class PlaybackControlSupportHelper extends PlaybackControlSupportGlue { 37 /** 38 * Change the location of the thumbs up/down controls 39 */ 40 private static final boolean THUMBS_PRIMARY = true; 41 42 private static final String FAUX_TITLE = "A short song of silence"; 43 private static final String FAUX_SUBTITLE = "2014"; 44 private static final int FAUX_DURATION = 33 * 1000; 45 46 // These should match the playback service FF behavior 47 private static int[] sFastForwardSpeeds = { 2, 3, 4, 5 }; 48 49 private boolean mIsPlaying; 50 private int mSpeed = PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED; 51 private long mStartTime; 52 private long mStartPosition = 0; 53 54 private PlaybackControlsRow.RepeatAction mRepeatAction; 55 private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction; 56 private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction; 57 private PlaybackControlsRow.PictureInPictureAction mPipAction; 58 59 private Handler mHandler = new Handler(); 60 private final Runnable mUpdateProgressRunnable = new Runnable() { 61 @Override 62 public void run() { 63 updateProgress(); 64 mHandler.postDelayed(this, getUpdatePeriod()); 65 } 66 }; 67 68 public PlaybackControlSupportHelper(Context context, PlaybackOverlaySupportFragment fragment) { 69 super(context, fragment, sFastForwardSpeeds); 70 mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context); 71 mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.OUTLINE); 72 mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context); 73 mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.OUTLINE); 74 mRepeatAction = new PlaybackControlsRow.RepeatAction(context); 75 mPipAction = new PlaybackControlsRow.PictureInPictureAction(context); 76 } 77 78 @Override 79 public PlaybackControlsRowPresenter createControlsRowAndPresenter() { 80 PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter(); 81 82 ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector()); 83 getControlsRow().setSecondaryActionsAdapter(adapter); 84 if (!THUMBS_PRIMARY) { 85 adapter.add(mThumbsDownAction); 86 } 87 if (android.os.Build.VERSION.SDK_INT > 23) { 88 adapter.add(mPipAction); 89 } 90 adapter.add(mRepeatAction); 91 if (!THUMBS_PRIMARY) { 92 adapter.add(mThumbsUpAction); 93 } 94 95 return presenter; 96 } 97 98 @Override 99 protected SparseArrayObjectAdapter createPrimaryActionsAdapter( 100 PresenterSelector presenterSelector) { 101 SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector); 102 if (THUMBS_PRIMARY) { 103 adapter.set(PlaybackControlSupportGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction); 104 adapter.set(PlaybackControlSupportGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction); 105 } 106 return adapter; 107 } 108 109 @Override 110 public void onActionClicked(Action action) { 111 if (shouldDispatchAction(action)) { 112 dispatchAction(action); 113 return; 114 } 115 super.onActionClicked(action); 116 } 117 118 @Override 119 public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 120 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) { 121 Action action = getControlsRow().getActionForKeyCode(keyEvent.getKeyCode()); 122 if (shouldDispatchAction(action)) { 123 dispatchAction(action); 124 return true; 125 } 126 } 127 return super.onKey(view, keyCode, keyEvent); 128 } 129 130 private boolean shouldDispatchAction(Action action) { 131 return action == mRepeatAction || action == mThumbsUpAction || action == mThumbsDownAction; 132 } 133 134 private void dispatchAction(Action action) { 135 Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show(); 136 PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action; 137 multiAction.nextIndex(); 138 notifyActionChanged(multiAction); 139 } 140 141 private void notifyActionChanged(PlaybackControlsRow.MultiAction action) { 142 int index; 143 index = getPrimaryActionsAdapter().indexOf(action); 144 if (index >= 0) { 145 getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1); 146 } else { 147 index = getSecondaryActionsAdapter().indexOf(action); 148 if (index >= 0) { 149 getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1); 150 } 151 } 152 } 153 154 private SparseArrayObjectAdapter getPrimaryActionsAdapter() { 155 return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter(); 156 } 157 158 private ArrayObjectAdapter getSecondaryActionsAdapter() { 159 return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter(); 160 } 161 162 @Override 163 public boolean hasValidMedia() { 164 return true; 165 } 166 167 @Override 168 public boolean isMediaPlaying() { 169 return mIsPlaying; 170 } 171 172 @Override 173 public CharSequence getMediaTitle() { 174 return FAUX_TITLE; 175 } 176 177 @Override 178 public CharSequence getMediaSubtitle() { 179 return FAUX_SUBTITLE; 180 } 181 182 @Override 183 public int getMediaDuration() { 184 return FAUX_DURATION; 185 } 186 187 @Override 188 public Drawable getMediaArt() { 189 return null; 190 } 191 192 @Override 193 public long getSupportedActions() { 194 return PlaybackControlSupportGlue.ACTION_PLAY_PAUSE | 195 PlaybackControlSupportGlue.ACTION_FAST_FORWARD | 196 PlaybackControlSupportGlue.ACTION_REWIND; 197 } 198 199 @Override 200 public int getCurrentSpeedId() { 201 return mSpeed; 202 } 203 204 @Override 205 public int getCurrentPosition() { 206 int speed; 207 if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED) { 208 speed = 0; 209 } else if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL) { 210 speed = 1; 211 } else if (mSpeed >= PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0) { 212 int index = mSpeed - PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0; 213 speed = getFastForwardSpeeds()[index]; 214 } else if (mSpeed <= -PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0) { 215 int index = -mSpeed - PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0; 216 speed = -getRewindSpeeds()[index]; 217 } else { 218 return -1; 219 } 220 long position = mStartPosition + 221 (System.currentTimeMillis() - mStartTime) * speed; 222 if (position > getMediaDuration()) { 223 position = getMediaDuration(); 224 onPlaybackComplete(true); 225 } else if (position < 0) { 226 position = 0; 227 onPlaybackComplete(false); 228 } 229 return (int) position; 230 } 231 232 void onPlaybackComplete(final boolean ended) { 233 mHandler.post(new Runnable() { 234 @Override 235 public void run() { 236 if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.NONE) { 237 pausePlayback(); 238 } else { 239 startPlayback(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL); 240 } 241 mStartPosition = 0; 242 onStateChanged(); 243 } 244 }); 245 } 246 247 @Override 248 protected void startPlayback(int speed) { 249 if (speed == mSpeed) { 250 return; 251 } 252 mStartPosition = getCurrentPosition(); 253 mSpeed = speed; 254 mIsPlaying = true; 255 mStartTime = System.currentTimeMillis(); 256 } 257 258 @Override 259 protected void pausePlayback() { 260 if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED) { 261 return; 262 } 263 mStartPosition = getCurrentPosition(); 264 mSpeed = PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED; 265 mIsPlaying = false; 266 } 267 268 @Override 269 protected void skipToNext() { 270 // Not supported 271 } 272 273 @Override 274 protected void skipToPrevious() { 275 // Not supported 276 } 277 278 @Override 279 public void enableProgressUpdating(boolean enable) { 280 mHandler.removeCallbacks(mUpdateProgressRunnable); 281 if (enable) { 282 mUpdateProgressRunnable.run(); 283 } 284 } 285 }; 286