PlayControlsRowView.java revision 0cc0713c1bf8027642987b750b80217569d2932a
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 17package com.android.tv.menu; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.text.TextUtils; 22import android.text.format.DateFormat; 23import android.util.AttributeSet; 24import android.view.View; 25import android.widget.TextView; 26import android.widget.Toast; 27import com.android.tv.MainActivity; 28import com.android.tv.R; 29import com.android.tv.TimeShiftManager; 30import com.android.tv.TimeShiftManager.TimeShiftActionId; 31import com.android.tv.TvSingletons; 32import com.android.tv.common.SoftPreconditions; 33import com.android.tv.common.feature.CommonFeatures; 34import com.android.tv.data.Program; 35import com.android.tv.data.api.Channel; 36import com.android.tv.dialog.HalfSizedDialogFragment; 37import com.android.tv.dvr.DvrDataManager; 38import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener; 39import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; 40import com.android.tv.dvr.DvrManager; 41import com.android.tv.dvr.data.ScheduledRecording; 42import com.android.tv.dvr.ui.DvrStopRecordingFragment; 43import com.android.tv.dvr.ui.DvrUiHelper; 44import com.android.tv.menu.Menu.MenuShowReason; 45import com.android.tv.ui.TunableTvView; 46 47public 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 105 public PlayControlsRowView(Context context) { 106 this(context, null); 107 } 108 109 public PlayControlsRowView(Context context, AttributeSet attrs) { 110 this(context, attrs, 0); 111 } 112 113 public PlayControlsRowView(Context context, AttributeSet attrs, int defStyleAttr) { 114 this(context, attrs, defStyleAttr, 0); 115 } 116 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 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 161 protected int getContentsViewId() { 162 return R.id.play_controls; 163 } 164 165 @Override 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 268 private boolean isCurrentChannelRecording() { 269 Channel currentChannel = mMainActivity.getCurrentChannel(); 270 return currentChannel != null 271 && mDvrManager != null 272 && mDvrManager.getCurrentRecording(currentChannel.getId()) != null; 273 } 274 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 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 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 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 426 private void updateMenuVisibility() { 427 boolean keepMenuVisible = 428 mTimeShiftManager.isAvailable() && !mTimeShiftManager.isNormalPlaying(); 429 getMenu().setKeepVisible(keepMenuVisible); 430 } 431 432 public void onPreselected() { 433 updateControls(true); 434 } 435 436 @Override 437 public void onSelected(boolean showTitle) { 438 super.onSelected(showTitle); 439 postHideRippleAnimation(); 440 } 441 442 @Override 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 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 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. */ 518 public void update() { 519 updateAll(false); 520 } 521 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 537 private void updateControls(boolean forceUpdate) { 538 if (forceUpdate || getContentsView().isShown()) { 539 updateTime(); 540 updateProgress(); 541 updateButtons(); 542 updateRecordButton(); 543 updateButtonMargin(); 544 } 545 } 546 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 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 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 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 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 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 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 710 private String getTimeString(long timeMs) { 711 return mTimeFormat.format(timeMs); 712 } 713 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 722 public void onDetachedFromWindow() { 723 super.onDetachedFromWindow(); 724 if (mDvrDataManager != null) { 725 mDvrDataManager.removeScheduledRecordingListener(mScheduledRecordingListener); 726 } 727 } 728 729 private void setTextIfNeeded(TextView textView, String text) { 730 if (!TextUtils.equals(textView.getText(), text)) { 731 textView.setText(text); 732 } 733 } 734} 735