• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.menu;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.text.TextUtils;
22 import android.text.format.DateFormat;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.widget.TextView;
26 import android.widget.Toast;
27 import com.android.tv.MainActivity;
28 import com.android.tv.R;
29 import com.android.tv.TimeShiftManager;
30 import com.android.tv.TimeShiftManager.TimeShiftActionId;
31 import com.android.tv.TvSingletons;
32 import com.android.tv.common.SoftPreconditions;
33 import com.android.tv.common.feature.CommonFeatures;
34 import com.android.tv.data.Program;
35 import com.android.tv.data.api.Channel;
36 import com.android.tv.dialog.HalfSizedDialogFragment;
37 import com.android.tv.dvr.DvrDataManager;
38 import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
39 import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
40 import com.android.tv.dvr.DvrManager;
41 import com.android.tv.dvr.data.ScheduledRecording;
42 import com.android.tv.dvr.ui.DvrStopRecordingFragment;
43 import com.android.tv.dvr.ui.DvrUiHelper;
44 import com.android.tv.menu.Menu.MenuShowReason;
45 import com.android.tv.ui.TunableTvView;
46 
47 public class PlayControlsRowView extends MenuRowView {
48     private static final int NORMAL_WIDTH_MAX_BUTTON_COUNT = 5;
49     // Dimensions
50     private final int mTimeIndicatorLeftMargin;
51     private final int mTimeTextLeftMargin;
52     private final int mTimelineWidth;
53     // Views
54     private TextView mBackgroundView;
55     private View mTimeIndicator;
56     private TextView mTimeText;
57     private PlaybackProgressBar mProgress;
58     private PlayControlsButton mJumpPreviousButton;
59     private PlayControlsButton mRewindButton;
60     private PlayControlsButton mPlayPauseButton;
61     private PlayControlsButton mFastForwardButton;
62     private PlayControlsButton mJumpNextButton;
63     private PlayControlsButton mRecordButton;
64     private TextView mProgramStartTimeText;
65     private TextView mProgramEndTimeText;
66     private TunableTvView mTvView;
67     private TimeShiftManager mTimeShiftManager;
68     private final DvrDataManager mDvrDataManager;
69     private final DvrManager mDvrManager;
70     private final MainActivity mMainActivity;
71 
72     private final java.text.DateFormat mTimeFormat;
73     private long mProgramStartTimeMs;
74     private long mProgramEndTimeMs;
75     private boolean mUseCompactLayout;
76     private final int mNormalButtonMargin;
77     private final int mCompactButtonMargin;
78 
79     private final String mUnavailableMessage;
80 
81     private final ScheduledRecordingListener mScheduledRecordingListener =
82             new ScheduledRecordingListener() {
83                 @Override
84                 public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {}
85 
86                 @Override
87                 public void onScheduledRecordingRemoved(
88                         ScheduledRecording... scheduledRecordings) {}
89 
90                 @Override
91                 public void onScheduledRecordingStatusChanged(
92                         ScheduledRecording... scheduledRecordings) {
93                     Channel currentChannel = mMainActivity.getCurrentChannel();
94                     if (currentChannel != null && isShown()) {
95                         for (ScheduledRecording schedule : scheduledRecordings) {
96                             if (schedule.getChannelId() == currentChannel.getId()) {
97                                 updateRecordButton();
98                                 break;
99                             }
100                         }
101                     }
102                 }
103             };
104 
PlayControlsRowView(Context context)105     public PlayControlsRowView(Context context) {
106         this(context, null);
107     }
108 
PlayControlsRowView(Context context, AttributeSet attrs)109     public PlayControlsRowView(Context context, AttributeSet attrs) {
110         this(context, attrs, 0);
111     }
112 
PlayControlsRowView(Context context, AttributeSet attrs, int defStyleAttr)113     public PlayControlsRowView(Context context, AttributeSet attrs, int defStyleAttr) {
114         this(context, attrs, defStyleAttr, 0);
115     }
116 
PlayControlsRowView( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)117     public PlayControlsRowView(
118             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
119         super(context, attrs, defStyleAttr, defStyleRes);
120         Resources res = context.getResources();
121         mTimeIndicatorLeftMargin =
122                 -res.getDimensionPixelSize(R.dimen.play_controls_time_indicator_width) / 2;
123         mTimeTextLeftMargin = -res.getDimensionPixelOffset(R.dimen.play_controls_time_width) / 2;
124         mTimelineWidth = res.getDimensionPixelSize(R.dimen.play_controls_width);
125         mTimeFormat = DateFormat.getTimeFormat(context);
126         mNormalButtonMargin = res.getDimensionPixelSize(R.dimen.play_controls_button_normal_margin);
127         mCompactButtonMargin =
128                 res.getDimensionPixelSize(R.dimen.play_controls_button_compact_margin);
129         if (CommonFeatures.DVR.isEnabled(context)) {
130             mDvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
131             mDvrManager = TvSingletons.getSingletons(context).getDvrManager();
132         } else {
133             mDvrDataManager = null;
134             mDvrManager = null;
135         }
136         mMainActivity = (MainActivity) context;
137         mUnavailableMessage = res.getString(R.string.play_controls_unavailable);
138     }
139 
140     @Override
onAttachedToWindow()141     public void onAttachedToWindow() {
142         super.onAttachedToWindow();
143         if (mDvrDataManager != null) {
144             mDvrDataManager.addScheduledRecordingListener(mScheduledRecordingListener);
145             if (!mDvrDataManager.isDvrScheduleLoadFinished()) {
146                 mDvrDataManager.addDvrScheduleLoadFinishedListener(
147                         new OnDvrScheduleLoadFinishedListener() {
148                             @Override
149                             public void onDvrScheduleLoadFinished() {
150                                 mDvrDataManager.removeDvrScheduleLoadFinishedListener(this);
151                                 if (isShown()) {
152                                     updateRecordButton();
153                                 }
154                             }
155                         });
156             }
157         }
158     }
159 
160     @Override
getContentsViewId()161     protected int getContentsViewId() {
162         return R.id.play_controls;
163     }
164 
165     @Override
onFinishInflate()166     protected void onFinishInflate() {
167         super.onFinishInflate();
168         // Clip the ViewGroup(body) to the rounded rectangle of outline.
169         findViewById(R.id.body).setClipToOutline(true);
170         mBackgroundView = (TextView) findViewById(R.id.background);
171         mTimeIndicator = findViewById(R.id.time_indicator);
172         mTimeText = (TextView) findViewById(R.id.time_text);
173         mProgress = (PlaybackProgressBar) findViewById(R.id.progress);
174         mJumpPreviousButton = (PlayControlsButton) findViewById(R.id.jump_previous);
175         mRewindButton = (PlayControlsButton) findViewById(R.id.rewind);
176         mPlayPauseButton = (PlayControlsButton) findViewById(R.id.play_pause);
177         mFastForwardButton = (PlayControlsButton) findViewById(R.id.fast_forward);
178         mJumpNextButton = (PlayControlsButton) findViewById(R.id.jump_next);
179         mRecordButton = (PlayControlsButton) findViewById(R.id.record);
180         mProgramStartTimeText = (TextView) findViewById(R.id.program_start_time);
181         mProgramEndTimeText = (TextView) findViewById(R.id.program_end_time);
182 
183         initializeButton(
184                 mJumpPreviousButton,
185                 R.drawable.lb_ic_skip_previous,
186                 R.string.play_controls_description_skip_previous,
187                 null,
188                 new Runnable() {
189                     @Override
190                     public void run() {
191                         if (mTimeShiftManager.isAvailable()) {
192                             mTimeShiftManager.jumpToPrevious();
193                             updateControls(true);
194                         }
195                     }
196                 });
197         initializeButton(
198                 mRewindButton,
199                 R.drawable.lb_ic_fast_rewind,
200                 R.string.play_controls_description_fast_rewind,
201                 null,
202                 new Runnable() {
203                     @Override
204                     public void run() {
205                         if (mTimeShiftManager.isAvailable()) {
206                             mTimeShiftManager.rewind();
207                             updateButtons();
208                         }
209                     }
210                 });
211         initializeButton(
212                 mPlayPauseButton,
213                 R.drawable.lb_ic_play,
214                 R.string.play_controls_description_play_pause,
215                 null,
216                 new Runnable() {
217                     @Override
218                     public void run() {
219                         if (mTimeShiftManager.isAvailable()) {
220                             mTimeShiftManager.togglePlayPause();
221                             updateButtons();
222                         }
223                     }
224                 });
225         initializeButton(
226                 mFastForwardButton,
227                 R.drawable.lb_ic_fast_forward,
228                 R.string.play_controls_description_fast_forward,
229                 null,
230                 new Runnable() {
231                     @Override
232                     public void run() {
233                         if (mTimeShiftManager.isAvailable()) {
234                             mTimeShiftManager.fastForward();
235                             updateButtons();
236                         }
237                     }
238                 });
239         initializeButton(
240                 mJumpNextButton,
241                 R.drawable.lb_ic_skip_next,
242                 R.string.play_controls_description_skip_next,
243                 null,
244                 new Runnable() {
245                     @Override
246                     public void run() {
247                         if (mTimeShiftManager.isAvailable()) {
248                             mTimeShiftManager.jumpToNext();
249                             updateControls(true);
250                         }
251                     }
252                 });
253         int color =
254                 getResources().getColor(R.color.play_controls_recording_icon_color_on_focus, null);
255         initializeButton(
256                 mRecordButton,
257                 R.drawable.ic_record_start,
258                 R.string.channels_item_record_start,
259                 color,
260                 new Runnable() {
261                     @Override
262                     public void run() {
263                         onRecordButtonClicked();
264                     }
265                 });
266     }
267 
isCurrentChannelRecording()268     private boolean isCurrentChannelRecording() {
269         Channel currentChannel = mMainActivity.getCurrentChannel();
270         return currentChannel != null
271                 && mDvrManager != null
272                 && mDvrManager.getCurrentRecording(currentChannel.getId()) != null;
273     }
274 
onRecordButtonClicked()275     private void onRecordButtonClicked() {
276         boolean isRecording = isCurrentChannelRecording();
277         Channel currentChannel = mMainActivity.getCurrentChannel();
278         TvSingletons.getSingletons(getContext())
279                 .getTracker()
280                 .sendMenuClicked(
281                         isRecording
282                                 ? R.string.channels_item_record_start
283                                 : R.string.channels_item_record_stop);
284         if (!isRecording) {
285             if (!(mDvrManager != null && mDvrManager.isChannelRecordable(currentChannel))) {
286                 Toast.makeText(
287                                 mMainActivity,
288                                 R.string.dvr_msg_cannot_record_channel,
289                                 Toast.LENGTH_SHORT)
290                         .show();
291             } else {
292                 Program program =
293                         TvSingletons.getSingletons(mMainActivity)
294                                 .getProgramDataManager()
295                                 .getCurrentProgram(currentChannel.getId());
296                 DvrUiHelper.checkStorageStatusAndShowErrorMessage(
297                         mMainActivity,
298                         currentChannel.getInputId(),
299                         new Runnable() {
300                             @Override
301                             public void run() {
302                                 DvrUiHelper.requestRecordingCurrentProgram(
303                                         mMainActivity, currentChannel, program, true);
304                             }
305                         });
306             }
307         } else if (currentChannel != null) {
308             DvrUiHelper.showStopRecordingDialog(
309                     mMainActivity,
310                     currentChannel.getId(),
311                     DvrStopRecordingFragment.REASON_USER_STOP,
312                     new HalfSizedDialogFragment.OnActionClickListener() {
313                         @Override
314                         public void onActionClick(long actionId) {
315                             if (actionId == DvrStopRecordingFragment.ACTION_STOP) {
316                                 ScheduledRecording currentRecording =
317                                         mDvrManager.getCurrentRecording(currentChannel.getId());
318                                 if (currentRecording != null) {
319                                     mDvrManager.stopRecording(currentRecording);
320                                 }
321                             }
322                         }
323                     });
324         }
325     }
326 
initializeButton( PlayControlsButton button, int imageResId, int descriptionId, Integer focusedIconColor, Runnable clickAction)327     private void initializeButton(
328             PlayControlsButton button,
329             int imageResId,
330             int descriptionId,
331             Integer focusedIconColor,
332             Runnable clickAction) {
333         button.setImageResId(imageResId);
334         button.setAction(clickAction);
335         if (focusedIconColor != null) {
336             button.setFocusedIconColor(focusedIconColor);
337         }
338         button.findViewById(R.id.button)
339                 .setContentDescription(getResources().getString(descriptionId));
340     }
341 
342     @Override
onBind(MenuRow row)343     public void onBind(MenuRow row) {
344         super.onBind(row);
345         PlayControlsRow playControlsRow = (PlayControlsRow) row;
346         mTvView = playControlsRow.getTvView();
347         mTimeShiftManager = playControlsRow.getTimeShiftManager();
348         mTimeShiftManager.setListener(
349                 new TimeShiftManager.Listener() {
350                     @Override
351                     public void onAvailabilityChanged() {
352                         updateMenuVisibility();
353                         PlayControlsRowView.this.updateAll(false);
354                     }
355 
356                     @Override
357                     public void onPlayStatusChanged(int status) {
358                         updateMenuVisibility();
359                         if (mTimeShiftManager.isAvailable()) {
360                             updateControls(false);
361                         }
362                     }
363 
364                     @Override
365                     public void onRecordTimeRangeChanged() {
366                         if (mTimeShiftManager.isAvailable()) {
367                             updateControls(false);
368                         }
369                     }
370 
371                     @Override
372                     public void onCurrentPositionChanged() {
373                         if (mTimeShiftManager.isAvailable()) {
374                             initializeTimeline();
375                             updateControls(false);
376                         }
377                     }
378 
379                     @Override
380                     public void onProgramInfoChanged() {
381                         if (mTimeShiftManager.isAvailable()) {
382                             initializeTimeline();
383                             updateControls(false);
384                         }
385                     }
386 
387                     @Override
388                     public void onActionEnabledChanged(
389                             @TimeShiftActionId int actionId, boolean enabled) {
390                         // Move focus to the play/pause button when the PREVIOUS, NEXT, REWIND or
391                         // FAST_FORWARD button is clicked and the button becomes disabled.
392                         // No need to update the UI here because the UI will be updated by other
393                         // callbacks.
394                         if (!enabled
395                                 && ((actionId
396                                                         == TimeShiftManager
397                                                                 .TIME_SHIFT_ACTION_ID_JUMP_TO_PREVIOUS
398                                                 && mJumpPreviousButton.hasFocus())
399                                         || (actionId == TimeShiftManager.TIME_SHIFT_ACTION_ID_REWIND
400                                                 && mRewindButton.hasFocus())
401                                         || (actionId
402                                                         == TimeShiftManager
403                                                                 .TIME_SHIFT_ACTION_ID_FAST_FORWARD
404                                                 && mFastForwardButton.hasFocus())
405                                         || (actionId
406                                                         == TimeShiftManager
407                                                                 .TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT
408                                                 && mJumpNextButton.hasFocus()))) {
409                             mPlayPauseButton.requestFocus();
410                         }
411                     }
412                 });
413         // force update to initialize everything
414         updateAll(true);
415     }
416 
initializeTimeline()417     private void initializeTimeline() {
418         Program program = mTimeShiftManager.getProgramAt(mTimeShiftManager.getCurrentPositionMs());
419         mProgramStartTimeMs = program.getStartTimeUtcMillis();
420         mProgramEndTimeMs = program.getEndTimeUtcMillis();
421         mProgress.setMax(mProgramEndTimeMs - mProgramStartTimeMs);
422         updateRecTimeText();
423         SoftPreconditions.checkArgument(mProgramStartTimeMs <= mProgramEndTimeMs);
424     }
425 
updateMenuVisibility()426     private void updateMenuVisibility() {
427         boolean keepMenuVisible =
428                 mTimeShiftManager.isAvailable() && !mTimeShiftManager.isNormalPlaying();
429         getMenu().setKeepVisible(keepMenuVisible);
430     }
431 
onPreselected()432     public void onPreselected() {
433         updateControls(true);
434     }
435 
436     @Override
onSelected(boolean showTitle)437     public void onSelected(boolean showTitle) {
438         super.onSelected(showTitle);
439         postHideRippleAnimation();
440     }
441 
442     @Override
initialize(@enuShowReason int reason)443     public void initialize(@MenuShowReason int reason) {
444         super.initialize(reason);
445         switch (reason) {
446             case Menu.REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS:
447                 if (mTimeShiftManager.isActionEnabled(
448                         TimeShiftManager.TIME_SHIFT_ACTION_ID_JUMP_TO_PREVIOUS)) {
449                     setInitialFocusView(mJumpPreviousButton);
450                 } else {
451                     setInitialFocusView(mPlayPauseButton);
452                 }
453                 break;
454             case Menu.REASON_PLAY_CONTROLS_REWIND:
455                 if (mTimeShiftManager.isActionEnabled(
456                         TimeShiftManager.TIME_SHIFT_ACTION_ID_REWIND)) {
457                     setInitialFocusView(mRewindButton);
458                 } else {
459                     setInitialFocusView(mPlayPauseButton);
460                 }
461                 break;
462             case Menu.REASON_PLAY_CONTROLS_FAST_FORWARD:
463                 if (mTimeShiftManager.isActionEnabled(
464                         TimeShiftManager.TIME_SHIFT_ACTION_ID_FAST_FORWARD)) {
465                     setInitialFocusView(mFastForwardButton);
466                 } else {
467                     setInitialFocusView(mPlayPauseButton);
468                 }
469                 break;
470             case Menu.REASON_PLAY_CONTROLS_JUMP_TO_NEXT:
471                 if (mTimeShiftManager.isActionEnabled(
472                         TimeShiftManager.TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT)) {
473                     setInitialFocusView(mJumpNextButton);
474                 } else {
475                     setInitialFocusView(mPlayPauseButton);
476                 }
477                 break;
478             case Menu.REASON_PLAY_CONTROLS_PLAY_PAUSE:
479             case Menu.REASON_PLAY_CONTROLS_PLAY:
480             case Menu.REASON_PLAY_CONTROLS_PAUSE:
481             default:
482                 setInitialFocusView(mPlayPauseButton);
483                 break;
484         }
485         postHideRippleAnimation();
486     }
487 
postHideRippleAnimation()488     private void postHideRippleAnimation() {
489         // Focus may be changed in another message if requestFocus is called in this message.
490         // After the focus is actually changed, hideRippleAnimation should run
491         // to reflect the result of the focus change. To be sure, hideRippleAnimation is posted.
492         post(
493                 new Runnable() {
494                     @Override
495                     public void run() {
496                         mJumpPreviousButton.hideRippleAnimation();
497                         mRewindButton.hideRippleAnimation();
498                         mPlayPauseButton.hideRippleAnimation();
499                         mFastForwardButton.hideRippleAnimation();
500                         mJumpNextButton.hideRippleAnimation();
501                     }
502                 });
503     }
504 
505     @Override
onChildFocusChange(View v, boolean hasFocus)506     protected void onChildFocusChange(View v, boolean hasFocus) {
507         super.onChildFocusChange(v, hasFocus);
508         if ((v.getParent().equals(mRewindButton) || v.getParent().equals(mFastForwardButton))
509                 && !hasFocus) {
510             if (mTimeShiftManager.getPlayStatus() == TimeShiftManager.PLAY_STATUS_PLAYING) {
511                 mTimeShiftManager.play();
512                 updateButtons();
513             }
514         }
515     }
516 
517     /** Updates the view contents. It is called from the PlayControlsRow. */
update()518     public void update() {
519         updateAll(false);
520     }
521 
updateAll(boolean forceUpdate)522     private void updateAll(boolean forceUpdate) {
523         if (mTimeShiftManager.isAvailable() && !mTvView.isScreenBlocked()) {
524             setEnabled(true);
525             initializeTimeline();
526             mBackgroundView.setEnabled(true);
527             setTextIfNeeded(mBackgroundView, null);
528         } else {
529             setEnabled(false);
530             mBackgroundView.setEnabled(false);
531             setTextIfNeeded(mBackgroundView, mUnavailableMessage);
532         }
533         // force the controls be updated no matter it's visible or not.
534         updateControls(forceUpdate);
535     }
536 
updateControls(boolean forceUpdate)537     private void updateControls(boolean forceUpdate) {
538         if (forceUpdate || getContentsView().isShown()) {
539             updateTime();
540             updateProgress();
541             updateButtons();
542             updateRecordButton();
543             updateButtonMargin();
544         }
545     }
546 
updateTime()547     private void updateTime() {
548         if (isEnabled()) {
549             mTimeText.setVisibility(View.VISIBLE);
550             mTimeIndicator.setVisibility(View.VISIBLE);
551         } else {
552             mTimeText.setVisibility(View.INVISIBLE);
553             mTimeIndicator.setVisibility(View.GONE);
554             return;
555         }
556         long currentPositionMs = mTimeShiftManager.getCurrentPositionMs();
557         int currentTimePositionPixel =
558                 convertDurationToPixel(currentPositionMs - mProgramStartTimeMs);
559         mTimeText.setTranslationX(currentTimePositionPixel + mTimeTextLeftMargin);
560         setTextIfNeeded(mTimeText, getTimeString(currentPositionMs));
561         mTimeIndicator.setTranslationX(currentTimePositionPixel + mTimeIndicatorLeftMargin);
562     }
563 
updateProgress()564     private void updateProgress() {
565         if (isEnabled()) {
566             long progressStartTimeMs =
567                     Math.min(
568                             mProgramEndTimeMs,
569                             Math.max(
570                                     mProgramStartTimeMs, mTimeShiftManager.getRecordStartTimeMs()));
571             long currentPlayingTimeMs =
572                     Math.min(
573                             mProgramEndTimeMs,
574                             Math.max(
575                                     mProgramStartTimeMs, mTimeShiftManager.getCurrentPositionMs()));
576             long progressEndTimeMs =
577                     Math.min(
578                             mProgramEndTimeMs,
579                             Math.max(mProgramStartTimeMs, mTimeShiftManager.getRecordEndTimeMs()));
580             mProgress.setProgressRange(
581                     progressStartTimeMs - mProgramStartTimeMs,
582                     progressEndTimeMs - mProgramStartTimeMs);
583             mProgress.setProgress(currentPlayingTimeMs - mProgramStartTimeMs);
584         } else {
585             mProgress.setProgressRange(0, 0);
586         }
587     }
588 
updateRecTimeText()589     private void updateRecTimeText() {
590         if (isEnabled()) {
591             mProgramStartTimeText.setVisibility(View.VISIBLE);
592             setTextIfNeeded(mProgramStartTimeText, getTimeString(mProgramStartTimeMs));
593             mProgramEndTimeText.setVisibility(View.VISIBLE);
594             setTextIfNeeded(mProgramEndTimeText, getTimeString(mProgramEndTimeMs));
595         } else {
596             mProgramStartTimeText.setVisibility(View.GONE);
597             mProgramEndTimeText.setVisibility(View.GONE);
598         }
599     }
600 
updateButtons()601     private void updateButtons() {
602         if (isEnabled()) {
603             mPlayPauseButton.setVisibility(View.VISIBLE);
604             mJumpPreviousButton.setVisibility(View.VISIBLE);
605             mJumpNextButton.setVisibility(View.VISIBLE);
606             mRewindButton.setVisibility(View.VISIBLE);
607             mFastForwardButton.setVisibility(View.VISIBLE);
608         } else {
609             mPlayPauseButton.setVisibility(View.GONE);
610             mJumpPreviousButton.setVisibility(View.GONE);
611             mJumpNextButton.setVisibility(View.GONE);
612             mRewindButton.setVisibility(View.GONE);
613             mFastForwardButton.setVisibility(View.GONE);
614             return;
615         }
616 
617         if (mTimeShiftManager.getPlayStatus() == TimeShiftManager.PLAY_STATUS_PAUSED) {
618             mPlayPauseButton.setImageResId(R.drawable.lb_ic_play);
619             mPlayPauseButton.setEnabled(
620                     mTimeShiftManager.isActionEnabled(TimeShiftManager.TIME_SHIFT_ACTION_ID_PLAY));
621         } else {
622             mPlayPauseButton.setImageResId(R.drawable.lb_ic_pause);
623             mPlayPauseButton.setEnabled(
624                     mTimeShiftManager.isActionEnabled(TimeShiftManager.TIME_SHIFT_ACTION_ID_PAUSE));
625         }
626         mJumpPreviousButton.setEnabled(
627                 mTimeShiftManager.isActionEnabled(
628                         TimeShiftManager.TIME_SHIFT_ACTION_ID_JUMP_TO_PREVIOUS));
629         mRewindButton.setEnabled(
630                 mTimeShiftManager.isActionEnabled(TimeShiftManager.TIME_SHIFT_ACTION_ID_REWIND));
631         mFastForwardButton.setEnabled(
632                 mTimeShiftManager.isActionEnabled(
633                         TimeShiftManager.TIME_SHIFT_ACTION_ID_FAST_FORWARD));
634         mJumpNextButton.setEnabled(
635                 mTimeShiftManager.isActionEnabled(
636                         TimeShiftManager.TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT));
637         mJumpPreviousButton.setVisibility(VISIBLE);
638         mJumpNextButton.setVisibility(VISIBLE);
639         updateButtonMargin();
640 
641         PlayControlsButton button;
642         if (mTimeShiftManager.getPlayDirection() == TimeShiftManager.PLAY_DIRECTION_FORWARD) {
643             mRewindButton.setLabel(null);
644             button = mFastForwardButton;
645         } else {
646             mFastForwardButton.setLabel(null);
647             button = mRewindButton;
648         }
649         if (mTimeShiftManager.getDisplayedPlaySpeed() == TimeShiftManager.PLAY_SPEED_1X) {
650             button.setLabel(null);
651         } else {
652             button.setLabel(
653                     getResources()
654                             .getString(
655                                     R.string.play_controls_speed,
656                                     mTimeShiftManager.getDisplayedPlaySpeed()));
657         }
658     }
659 
updateRecordButton()660     private void updateRecordButton() {
661         if (isEnabled()) {
662             mRecordButton.setVisibility(VISIBLE);
663         } else {
664             mRecordButton.setVisibility(GONE);
665             return;
666         }
667         if (!(mDvrManager != null
668                 && mDvrManager.isChannelRecordable(mMainActivity.getCurrentChannel()))) {
669             mRecordButton.setVisibility(View.GONE);
670             updateButtonMargin();
671             return;
672         }
673         mRecordButton.setVisibility(View.VISIBLE);
674         updateButtonMargin();
675         if (isCurrentChannelRecording()) {
676             mRecordButton.setImageResId(R.drawable.ic_record_stop);
677         } else {
678             mRecordButton.setImageResId(R.drawable.ic_record_start);
679         }
680     }
681 
updateButtonMargin()682     private void updateButtonMargin() {
683         int numOfVisibleButtons =
684                 (mJumpPreviousButton.getVisibility() == View.VISIBLE ? 1 : 0)
685                         + (mRewindButton.getVisibility() == View.VISIBLE ? 1 : 0)
686                         + (mPlayPauseButton.getVisibility() == View.VISIBLE ? 1 : 0)
687                         + (mFastForwardButton.getVisibility() == View.VISIBLE ? 1 : 0)
688                         + (mJumpNextButton.getVisibility() == View.VISIBLE ? 1 : 0)
689                         + (mRecordButton.getVisibility() == View.VISIBLE ? 1 : 0);
690         boolean useCompactLayout = numOfVisibleButtons > NORMAL_WIDTH_MAX_BUTTON_COUNT;
691         if (mUseCompactLayout == useCompactLayout) {
692             return;
693         }
694         mUseCompactLayout = useCompactLayout;
695         int margin = mUseCompactLayout ? mCompactButtonMargin : mNormalButtonMargin;
696         updateButtonMargin(mJumpPreviousButton, margin);
697         updateButtonMargin(mRewindButton, margin);
698         updateButtonMargin(mPlayPauseButton, margin);
699         updateButtonMargin(mFastForwardButton, margin);
700         updateButtonMargin(mJumpNextButton, margin);
701         updateButtonMargin(mRecordButton, margin);
702     }
703 
updateButtonMargin(PlayControlsButton button, int margin)704     private void updateButtonMargin(PlayControlsButton button, int margin) {
705         MarginLayoutParams params = (MarginLayoutParams) button.getLayoutParams();
706         params.setMargins(margin, 0, margin, 0);
707         button.setLayoutParams(params);
708     }
709 
getTimeString(long timeMs)710     private String getTimeString(long timeMs) {
711         return mTimeFormat.format(timeMs);
712     }
713 
convertDurationToPixel(long duration)714     private int convertDurationToPixel(long duration) {
715         if (mProgramEndTimeMs <= mProgramStartTimeMs) {
716             return 0;
717         }
718         return (int) (duration * mTimelineWidth / (mProgramEndTimeMs - mProgramStartTimeMs));
719     }
720 
721     @Override
onDetachedFromWindow()722     public void onDetachedFromWindow() {
723         super.onDetachedFromWindow();
724         if (mDvrDataManager != null) {
725             mDvrDataManager.removeScheduledRecordingListener(mScheduledRecordingListener);
726         }
727     }
728 
setTextIfNeeded(TextView textView, String text)729     private void setTextIfNeeded(TextView textView, String text) {
730         if (!TextUtils.equals(textView.getText(), text)) {
731             textView.setText(text);
732         }
733     }
734 }
735