Home | History | Annotate | Download | only in playback
      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