1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.example.android.tv.channelsprograms.playback; 16 17 import android.content.Context; 18 import android.os.Handler; 19 import android.support.v17.leanback.media.PlaybackTransportControlGlue; 20 import android.support.v17.leanback.media.PlayerAdapter; 21 import android.support.v17.leanback.widget.Action; 22 import android.support.v17.leanback.widget.ArrayObjectAdapter; 23 import android.support.v17.leanback.widget.PlaybackControlsRow; 24 import android.view.KeyEvent; 25 import android.view.View; 26 import android.widget.Toast; 27 28 /** 29 * Handles common primary and secondary actions such as repeat, thumbs up/down, picture in picture, 30 * and closed captions. 31 */ 32 class SimplePlaybackTransportControlGlue<T extends PlayerAdapter> 33 extends PlaybackTransportControlGlue<T> { 34 35 private PlaybackControlsRow.RepeatAction mRepeatAction; 36 private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction; 37 private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction; 38 private PlaybackControlsRow.PictureInPictureAction mPipAction; 39 private PlaybackControlsRow.ClosedCaptioningAction mClosedCaptioningAction; 40 private Handler mHandler = new Handler(); 41 42 public SimplePlaybackTransportControlGlue(Context context, T impl) { 43 super(context, impl); 44 mClosedCaptioningAction = new PlaybackControlsRow.ClosedCaptioningAction(context); 45 mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context); 46 mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.OUTLINE); 47 mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context); 48 mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.OUTLINE); 49 mRepeatAction = new PlaybackControlsRow.RepeatAction(context); 50 mPipAction = new PlaybackControlsRow.PictureInPictureAction(context); 51 } 52 53 @Override 54 protected void onCreatePrimaryActions(ArrayObjectAdapter adapter) { 55 super.onCreatePrimaryActions(adapter); 56 adapter.add(mRepeatAction); 57 adapter.add(mClosedCaptioningAction); 58 } 59 60 @Override 61 protected void onCreateSecondaryActions(ArrayObjectAdapter adapter) { 62 super.onCreateSecondaryActions(adapter); 63 adapter.add(mThumbsUpAction); 64 adapter.add(mThumbsDownAction); 65 adapter.add(mPipAction); 66 } 67 68 @Override 69 public void onActionClicked(Action action) { 70 if (shouldDispatchAction(action)) { 71 dispatchAction(action, getPrimaryActionsAdapter()); 72 dispatchAction(action, getSecondaryActionsAdapter()); 73 return; 74 } 75 super.onActionClicked(action); 76 } 77 78 @Override 79 public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 80 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) { 81 boolean dispatched = dispatchAction(keyEvent, getPrimaryActionsAdapter()); 82 dispatched |= dispatchAction(keyEvent, getSecondaryActionsAdapter()); 83 if (dispatched) { 84 return true; 85 } 86 } 87 return super.onKey(view, keyCode, keyEvent); 88 } 89 90 private boolean dispatchAction(KeyEvent keyEvent, ArrayObjectAdapter adapter) { 91 Action action = getControlsRow().getActionForKeyCode(adapter, keyEvent.getKeyCode()); 92 if (shouldDispatchAction(action)) { 93 dispatchAction(action, adapter); 94 return true; 95 } 96 return false; 97 } 98 99 private boolean shouldDispatchAction(Action action) { 100 return action == mRepeatAction || action == mThumbsUpAction || action == mThumbsDownAction; 101 } 102 103 private void dispatchAction(Action action, ArrayObjectAdapter adapter) { 104 Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show(); 105 PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action; 106 multiAction.nextIndex(); 107 notifyActionChanged(multiAction, adapter); 108 } 109 110 private void notifyActionChanged( 111 PlaybackControlsRow.MultiAction action, ArrayObjectAdapter adapter) { 112 if (adapter != null) { 113 int index = adapter.indexOf(action); 114 if (index >= 0) { 115 adapter.notifyArrayItemRangeChanged(index, 1); 116 } 117 } 118 } 119 120 private ArrayObjectAdapter getPrimaryActionsAdapter() { 121 if (getControlsRow() == null) { 122 return null; 123 } 124 return (ArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter(); 125 } 126 127 private ArrayObjectAdapter getSecondaryActionsAdapter() { 128 if (getControlsRow() == null) { 129 return null; 130 } 131 return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter(); 132 } 133 134 @Override 135 protected void onPlayCompleted() { 136 super.onPlayCompleted(); 137 mHandler.post( 138 () -> { 139 if (mRepeatAction.getIndex() != PlaybackControlsRow.RepeatAction.INDEX_NONE) { 140 play(); 141 } 142 }); 143 } 144 145 /** 146 * Sets the behavior for the repeat action. The possible modes are 147 * 148 * <ul> 149 * <li>{@link PlaybackControlsRow.RepeatAction#INDEX_NONE} 150 * <li>{@link PlaybackControlsRow.RepeatAction#INDEX_ALL} 151 * <li>{@link PlaybackControlsRow.RepeatAction#INDEX_ONE} 152 * </ul> 153 * 154 * @param mode for repeat behavior. 155 */ 156 public void setRepeatMode(int mode) { 157 mRepeatAction.setIndex(mode); 158 notifyActionChanged(mRepeatAction, getPrimaryActionsAdapter()); 159 } 160 } 161