From f518cb660c52bc1244a9baeab813f3f95ad3ad65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6rkem=20G=C3=BCcl=C3=BC?= Date: Mon, 16 Jan 2023 12:12:45 +0100 Subject: [PATCH] Removing files outside of library --- .../demo/DefaultThumbnailProvider.java | 194 ---- .../demo/DefaultThumbnailTimeBar.java | 1026 ----------------- .../exoplayer2/demo/PlayerActivity.java | 6 +- .../exoplayer2/demo/ThumbnailProvider.java | 9 - .../layout/exo_styled_player_control_view.xml | 152 --- .../thumbnail/ThumbnailDescription.java | 13 +- .../source/dash/manifest/DashManifest.java | 3 + 7 files changed, 14 insertions(+), 1389 deletions(-) delete mode 100644 demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java delete mode 100644 demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailTimeBar.java delete mode 100644 demos/main/src/main/java/com/google/android/exoplayer2/demo/ThumbnailProvider.java delete mode 100644 demos/main/src/main/res/layout/exo_styled_player_control_view.xml diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java deleted file mode 100644 index 2006d68990..0000000000 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.google.android.exoplayer2.demo; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.AsyncTask; -import android.util.LruCache; -import android.view.View; -import androidx.annotation.Nullable; -import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.source.dash.manifest.DashManifest; -import com.google.android.exoplayer2.thumbnail.ThumbnailDescription; -import com.google.android.exoplayer2.util.Log; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.List; - -public class DefaultThumbnailProvider implements ThumbnailProvider { - - private static final String TAG_DEBUG = DefaultThumbnailProvider.class.getSimpleName(); - - private LruCache bitmapCache; - private View parent; - - //dummy bitmap to indicate that a download is already triggered but not finished yet - private final Bitmap dummyBitmap = Bitmap.createBitmap(1,1,Bitmap.Config.ARGB_8888); - @Nullable ExoPlayer exoPlayer; - - public DefaultThumbnailProvider(ExoPlayer exoPlayer, View view) { - this.exoPlayer = exoPlayer; - - this.parent = view; - - final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); - final int cacheSize = maxMemory / 4; - bitmapCache = new LruCache(cacheSize) { - @Override - protected int sizeOf(String key, Bitmap bitmap) { - return bitmap.getByteCount() / 1024; - } - }; - } - - public Bitmap getThumbnail(long position) { - return getThumbnail(position, true); - } - - private Bitmap getThumbnail(long position, boolean retrigger) { - if (exoPlayer != null) { - Object manifest = exoPlayer.getCurrentManifest(); - - ThumbnailDescription thumbnailDescription = null; - if (manifest instanceof DashManifest) { - DashManifest dashManifest = (DashManifest) manifest; - List thumbnailDescs = dashManifest.getThumbnailDescriptions(position); - //selected thumbnail description with lowest bitrate - for (ThumbnailDescription desc : thumbnailDescs) { - if (thumbnailDescription == null || thumbnailDescription.getBitrate() > desc.getBitrate()) { - thumbnailDescription = desc; - } - } - if (bitmapNotAvailableOrDownloadNotTriggeredYet(thumbnailDescription.getUri())) { - this.initThumbnailSource(thumbnailDescription); - return null; - } - } - - if (retrigger) { - //also download next and prev thumbnails to have a nicer UI user experience - getThumbnail(thumbnailDescription.getStartTimeMs() + thumbnailDescription.getDurationMs(), false); - getThumbnail(thumbnailDescription.getStartTimeMs() - thumbnailDescription.getDurationMs(), false); - } - - return getThumbnailInternal(position, thumbnailDescription); - } - return null; - } - - private boolean bitmapNotAvailableOrDownloadNotTriggeredYet(Uri uri) { - Bitmap tmp = bitmapCache.get(uri.toString()); - if (tmp != null) return false; - return true; - } - - private Bitmap getThumbnailInternal(long position, ThumbnailDescription thumbnailDescription) { - if (thumbnailDescription == null) return null; - - Bitmap thumbnailSource = bitmapCache.get(thumbnailDescription.getUri().toString()); - - if (thumbnailSource == null || thumbnailSource.getWidth() == 1) return null; - - if (position < thumbnailDescription.getStartTimeMs() || position > thumbnailDescription.getStartTimeMs() + thumbnailDescription.getDurationMs()) return null; - - int count = thumbnailDescription.getTileCountHorizontal() * thumbnailDescription.getTileCountVertical(); - - int durationPerImage = (int)(thumbnailDescription.getDurationMs() / count); - - int imageNumberToUseWithinTile = (int)((position - thumbnailDescription.getStartTimeMs()) / durationPerImage); - - //handle special case if position == duration - if (imageNumberToUseWithinTile > count-1) imageNumberToUseWithinTile = count-1; - - int intRowToUse = (int)(imageNumberToUseWithinTile / thumbnailDescription.getTileCountHorizontal()); - - int intColToUse = imageNumberToUseWithinTile - intRowToUse * thumbnailDescription.getTileCountHorizontal(); - - double thumbnailWidth = (double) thumbnailDescription.getImageWidth() / thumbnailDescription.getTileCountHorizontal(); - double thumbnailHeight = (double) thumbnailDescription.getImageHeight() / thumbnailDescription.getTileCountVertical(); - - int cropXLeft = (int)Math.round(intColToUse * thumbnailWidth); - int cropYTop = (int)Math.round(intRowToUse * thumbnailHeight); - - if (cropXLeft + thumbnailWidth <= thumbnailSource.getWidth() && cropYTop + thumbnailHeight <= thumbnailSource.getHeight()) { - return Bitmap.createBitmap(thumbnailSource - , cropXLeft, cropYTop, (int) thumbnailWidth, (int) thumbnailHeight); - } - else { - Log.d(TAG_DEBUG, "Image does not have expected (" + thumbnailDescription.getImageWidth() + "x" + thumbnailDescription.getImageHeight() + ") dimensions to crop. Source " + thumbnailDescription.getUri()); - return null; - } - } - - private synchronized void initThumbnailSource(ThumbnailDescription thumbnailDescription){ - String path = thumbnailDescription.getUri().toString(); - if (path == null) return; - - if (bitmapCache.get(path) != null) return; - bitmapCache.put(path, dummyBitmap); - - RetrieveThumbnailImageTask currentTask = new RetrieveThumbnailImageTask(); - currentTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, path); - } - - class RetrieveThumbnailImageTask extends AsyncTask { - - String downloadedUrl; - - RetrieveThumbnailImageTask() { - - } - - @Override - protected void onCancelled() { - super.onCancelled(); - if (downloadedUrl != null) bitmapCache.remove(downloadedUrl); - } - - protected Bitmap doInBackground(String... urls) { - downloadedUrl = urls[0]; - InputStream in =null; - Bitmap thumbnailToDownload=null; - int responseCode = -1; - - try{ - URL url = new URL(downloadedUrl); - if (!isCancelled()) { - HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection(); - httpURLConnection.setDoInput(true); - httpURLConnection.connect(); - responseCode = httpURLConnection.getResponseCode(); - if(responseCode == HttpURLConnection.HTTP_OK) - { - if (!isCancelled()) { - in = httpURLConnection.getInputStream(); - if (!isCancelled()) { - thumbnailToDownload = BitmapFactory.decodeStream(in); - } - in.close(); - } - } - } - - } - catch(Exception ex){ - bitmapCache.remove(downloadedUrl); - System.out.println(ex); - } - - return thumbnailToDownload; - } - - protected void onPostExecute(Bitmap downloadedThumbnail) { - if (downloadedThumbnail != null) { - bitmapCache.put(downloadedUrl, downloadedThumbnail); - if (parent != null) parent.invalidate(); - } - else { - bitmapCache.remove(downloadedUrl); - } - } - } - -} diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailTimeBar.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailTimeBar.java deleted file mode 100644 index a3e75923e5..0000000000 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailTimeBar.java +++ /dev/null @@ -1,1026 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.demo; - -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewParent; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; -import androidx.annotation.ColorInt; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ui.TimeBar; -import com.google.android.exoplayer2.util.Assertions; -import com.google.android.exoplayer2.util.Util; -import java.util.Collections; -import java.util.Formatter; -import java.util.Locale; -import java.util.concurrent.CopyOnWriteArraySet; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; - -/** - * A time bar that shows a current position, buffered position, duration and ad markers. - * - *

A DefaultTimeBar can be customized by setting attributes, as outlined below. - * - *

Attributes

- * - * The following attributes can be set on a DefaultTimeBar when used in a layout XML file: - * - *
    - *
  • {@code bar_height} - Dimension for the height of the time bar. - *
      - *
    • Default: {@link #DEFAULT_BAR_HEIGHT_DP} - *
    - *
  • {@code touch_target_height} - Dimension for the height of the area in which touch - * interactions with the time bar are handled. If no height is specified, this also determines - * the height of the view. - *
      - *
    • Default: {@link #DEFAULT_TOUCH_TARGET_HEIGHT_DP} - *
    - *
  • {@code ad_marker_width} - Dimension for the width of any ad markers shown on the - * bar. Ad markers are superimposed on the time bar to show the times at which ads will play. - *
      - *
    • Default: {@link #DEFAULT_AD_MARKER_WIDTH_DP} - *
    - *
  • {@code scrubber_enabled_size} - Dimension for the diameter of the circular scrubber - * handle when scrubbing is enabled but not in progress. Set to zero if no scrubber handle - * should be shown. - *
      - *
    • Default: {@link #DEFAULT_SCRUBBER_ENABLED_SIZE_DP} - *
    - *
  • {@code scrubber_disabled_size} - Dimension for the diameter of the circular scrubber - * handle when scrubbing isn't enabled. Set to zero if no scrubber handle should be shown. - *
      - *
    • Default: {@link #DEFAULT_SCRUBBER_DISABLED_SIZE_DP} - *
    - *
  • {@code scrubber_dragged_size} - Dimension for the diameter of the circular scrubber - * handle when scrubbing is in progress. Set to zero if no scrubber handle should be shown. - *
      - *
    • Default: {@link #DEFAULT_SCRUBBER_DRAGGED_SIZE_DP} - *
    - *
  • {@code scrubber_drawable} - Optional reference to a drawable to draw for the - * scrubber handle. If set, this overrides the default behavior, which is to draw a circle for - * the scrubber handle. - *
  • {@code played_color} - Color for the portion of the time bar representing media - * before the current playback position. - *
      - *
    • Corresponding method: {@link #setPlayedColor(int)} - *
    • Default: {@link #DEFAULT_PLAYED_COLOR} - *
    - *
  • {@code scrubber_color} - Color for the scrubber handle. - *
      - *
    • Corresponding method: {@link #setScrubberColor(int)} - *
    • Default: {@link #DEFAULT_SCRUBBER_COLOR} - *
    - *
  • {@code buffered_color} - Color for the portion of the time bar after the current - * played position up to the current buffered position. - *
      - *
    • Corresponding method: {@link #setBufferedColor(int)} - *
    • Default: {@link #DEFAULT_BUFFERED_COLOR} - *
    - *
  • {@code unplayed_color} - Color for the portion of the time bar after the current - * buffered position. - *
      - *
    • Corresponding method: {@link #setUnplayedColor(int)} - *
    • Default: {@link #DEFAULT_UNPLAYED_COLOR} - *
    - *
  • {@code ad_marker_color} - Color for unplayed ad markers. - *
      - *
    • Corresponding method: {@link #setAdMarkerColor(int)} - *
    • Default: {@link #DEFAULT_AD_MARKER_COLOR} - *
    - *
  • {@code played_ad_marker_color} - Color for played ad markers. - *
      - *
    • Corresponding method: {@link #setPlayedAdMarkerColor(int)} - *
    • Default: {@link #DEFAULT_PLAYED_AD_MARKER_COLOR} - *
    - *
- */ -public class DefaultThumbnailTimeBar extends View implements TimeBar { - - /** Default height for the time bar, in dp. */ - public static final int DEFAULT_BAR_HEIGHT_DP = 4; - /** Default height for the touch target, in dp. */ - public static final int DEFAULT_TOUCH_TARGET_HEIGHT_DP = 26; - /** Default width for ad markers, in dp. */ - public static final int DEFAULT_AD_MARKER_WIDTH_DP = 4; - /** Default diameter for the scrubber when enabled, in dp. */ - public static final int DEFAULT_SCRUBBER_ENABLED_SIZE_DP = 12; - /** Default diameter for the scrubber when disabled, in dp. */ - public static final int DEFAULT_SCRUBBER_DISABLED_SIZE_DP = 0; - /** Default diameter for the scrubber when dragged, in dp. */ - public static final int DEFAULT_SCRUBBER_DRAGGED_SIZE_DP = 16; - /** Default color for the played portion of the time bar. */ - public static final int DEFAULT_PLAYED_COLOR = 0xFFFFFFFF; - /** Default color for the unplayed portion of the time bar. */ - public static final int DEFAULT_UNPLAYED_COLOR = 0x33FFFFFF; - /** Default color for the buffered portion of the time bar. */ - public static final int DEFAULT_BUFFERED_COLOR = 0xCCFFFFFF; - /** Default color for the scrubber handle. */ - public static final int DEFAULT_SCRUBBER_COLOR = 0xFFFFFFFF; - /** Default color for ad markers. */ - public static final int DEFAULT_AD_MARKER_COLOR = 0xB2FFFF00; - /** Default color for played ad markers. */ - public static final int DEFAULT_PLAYED_AD_MARKER_COLOR = 0x33FFFF00; - - /** Vertical gravity for progress bar to be located at the center in the view. */ - public static final int BAR_GRAVITY_CENTER = 0; - /** Vertical gravity for progress bar to be located at the bottom in the view. */ - public static final int BAR_GRAVITY_BOTTOM = 1; - - /** The threshold in dps above the bar at which touch events trigger fine scrub mode. */ - private static final int FINE_SCRUB_Y_THRESHOLD_DP = -50; - /** The ratio by which times are reduced in fine scrub mode. */ - private static final int FINE_SCRUB_RATIO = 3; - /** - * The time after which the scrubbing listener is notified that scrubbing has stopped after - * performing an incremental scrub using key input. - */ - private static final long STOP_SCRUBBING_TIMEOUT_MS = 1000; - - private static final int DEFAULT_INCREMENT_COUNT = 20; - - private static final float SHOWN_SCRUBBER_SCALE = 1.0f; - private static final float HIDDEN_SCRUBBER_SCALE = 0.0f; - - /** - * The name of the Android SDK view that most closely resembles this custom view. Used as the - * class name for accessibility. - */ - private static final String ACCESSIBILITY_CLASS_NAME = "android.widget.SeekBar"; - - private final Rect seekBounds; - private final Rect progressBar; - private final Rect bufferedBar; - private final Rect scrubberBar; - private final Paint playedPaint; - private final Paint bufferedPaint; - private final Paint unplayedPaint; - private final Paint adMarkerPaint; - private final Paint playedAdMarkerPaint; - private final Paint scrubberPaint; - @Nullable private final Drawable scrubberDrawable; - private final int barHeight; - private final int touchTargetHeight; - private final int barGravity; - private final int adMarkerWidth; - private final int scrubberEnabledSize; - private final int scrubberDisabledSize; - private final int scrubberDraggedSize; - private final int scrubberPadding; - private final int fineScrubYThreshold; - private final StringBuilder formatBuilder; - private final Formatter formatter; - private final Runnable stopScrubbingRunnable; - private final CopyOnWriteArraySet listeners; - private final Point touchPosition; - private final float density; - - private int keyCountIncrement; - private long keyTimeIncrement; - private int lastCoarseScrubXPosition; - private @MonotonicNonNull Rect lastExclusionRectangle; - - private ValueAnimator scrubberScalingAnimator; - private float scrubberScale; - private boolean scrubberPaddingDisabled; - private boolean scrubbing; - private long scrubPosition; - private long duration; - private long position; - private long bufferedPosition; - private int adGroupCount; - @Nullable private long[] adGroupTimesMs; - @Nullable private boolean[] playedAdGroups; - - private ThumbnailProvider thumbnailUtils; - //TODO put in ressource file - int targetThumbnailHeightInDp = 80; - - public DefaultThumbnailTimeBar(Context context) { - this(context, null); - } - - public DefaultThumbnailTimeBar(Context context, @Nullable AttributeSet attrs) { - this(context, attrs, 0); - } - - public DefaultThumbnailTimeBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, attrs); - } - - public DefaultThumbnailTimeBar( - Context context, - @Nullable AttributeSet attrs, - int defStyleAttr, - @Nullable AttributeSet timebarAttrs) { - this(context, attrs, defStyleAttr, timebarAttrs, 0); - } - - // Suppress warnings due to usage of View methods in the constructor. - @SuppressWarnings("nullness:method.invocation") - public DefaultThumbnailTimeBar( - Context context, - @Nullable AttributeSet attrs, - int defStyleAttr, - @Nullable AttributeSet timebarAttrs, - int defStyleRes) { - super(context, attrs, defStyleAttr); - seekBounds = new Rect(); - progressBar = new Rect(); - bufferedBar = new Rect(); - scrubberBar = new Rect(); - playedPaint = new Paint(); - bufferedPaint = new Paint(); - unplayedPaint = new Paint(); - adMarkerPaint = new Paint(); - playedAdMarkerPaint = new Paint(); - scrubberPaint = new Paint(); - scrubberPaint.setAntiAlias(true); - listeners = new CopyOnWriteArraySet<>(); - touchPosition = new Point(); - - // Calculate the dimensions and paints for drawn elements. - Resources res = context.getResources(); - DisplayMetrics displayMetrics = res.getDisplayMetrics(); - density = displayMetrics.density; - fineScrubYThreshold = dpToPx(density, FINE_SCRUB_Y_THRESHOLD_DP); - int defaultBarHeight = dpToPx(density, DEFAULT_BAR_HEIGHT_DP); - int defaultTouchTargetHeight = dpToPx(density, DEFAULT_TOUCH_TARGET_HEIGHT_DP); - int defaultAdMarkerWidth = dpToPx(density, DEFAULT_AD_MARKER_WIDTH_DP); - int defaultScrubberEnabledSize = dpToPx(density, DEFAULT_SCRUBBER_ENABLED_SIZE_DP); - int defaultScrubberDisabledSize = dpToPx(density, DEFAULT_SCRUBBER_DISABLED_SIZE_DP); - int defaultScrubberDraggedSize = dpToPx(density, DEFAULT_SCRUBBER_DRAGGED_SIZE_DP); - if (timebarAttrs != null) { - TypedArray a = - context - .getTheme() - .obtainStyledAttributes( - timebarAttrs, com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar, defStyleAttr, defStyleRes); - try { - scrubberDrawable = a.getDrawable(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_scrubber_drawable); - if (scrubberDrawable != null) { - setDrawableLayoutDirection(scrubberDrawable); - defaultTouchTargetHeight = - Math.max(scrubberDrawable.getMinimumHeight(), defaultTouchTargetHeight); - } - barHeight = - a.getDimensionPixelSize(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_bar_height, defaultBarHeight); - touchTargetHeight = - a.getDimensionPixelSize( - com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_touch_target_height, defaultTouchTargetHeight); - barGravity = a.getInt(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_bar_gravity, BAR_GRAVITY_CENTER); - adMarkerWidth = - a.getDimensionPixelSize( - com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_ad_marker_width, defaultAdMarkerWidth); - scrubberEnabledSize = - a.getDimensionPixelSize( - com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_scrubber_enabled_size, defaultScrubberEnabledSize); - scrubberDisabledSize = - a.getDimensionPixelSize( - com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_scrubber_disabled_size, defaultScrubberDisabledSize); - scrubberDraggedSize = - a.getDimensionPixelSize( - com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_scrubber_dragged_size, defaultScrubberDraggedSize); - int playedColor = a.getInt(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_played_color, DEFAULT_PLAYED_COLOR); - int scrubberColor = - a.getInt(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_scrubber_color, DEFAULT_SCRUBBER_COLOR); - int bufferedColor = - a.getInt(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_buffered_color, DEFAULT_BUFFERED_COLOR); - int unplayedColor = - a.getInt(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_unplayed_color, DEFAULT_UNPLAYED_COLOR); - int adMarkerColor = - a.getInt(com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_ad_marker_color, DEFAULT_AD_MARKER_COLOR); - int playedAdMarkerColor = - a.getInt( - com.google.android.exoplayer2.ui.R.styleable.DefaultTimeBar_played_ad_marker_color, DEFAULT_PLAYED_AD_MARKER_COLOR); - playedPaint.setColor(playedColor); - scrubberPaint.setColor(scrubberColor); - bufferedPaint.setColor(bufferedColor); - unplayedPaint.setColor(unplayedColor); - adMarkerPaint.setColor(adMarkerColor); - playedAdMarkerPaint.setColor(playedAdMarkerColor); - } finally { - a.recycle(); - } - } else { - barHeight = defaultBarHeight; - touchTargetHeight = defaultTouchTargetHeight; - barGravity = BAR_GRAVITY_CENTER; - adMarkerWidth = defaultAdMarkerWidth; - scrubberEnabledSize = defaultScrubberEnabledSize; - scrubberDisabledSize = defaultScrubberDisabledSize; - scrubberDraggedSize = defaultScrubberDraggedSize; - playedPaint.setColor(DEFAULT_PLAYED_COLOR); - scrubberPaint.setColor(DEFAULT_SCRUBBER_COLOR); - bufferedPaint.setColor(DEFAULT_BUFFERED_COLOR); - unplayedPaint.setColor(DEFAULT_UNPLAYED_COLOR); - adMarkerPaint.setColor(DEFAULT_AD_MARKER_COLOR); - playedAdMarkerPaint.setColor(DEFAULT_PLAYED_AD_MARKER_COLOR); - scrubberDrawable = null; - } - formatBuilder = new StringBuilder(); - formatter = new Formatter(formatBuilder, Locale.getDefault()); - stopScrubbingRunnable = () -> stopScrubbing(/* canceled= */ false); - if (scrubberDrawable != null) { - scrubberPadding = (scrubberDrawable.getMinimumWidth() + 1) / 2; - } else { - scrubberPadding = - (Math.max(scrubberDisabledSize, Math.max(scrubberEnabledSize, scrubberDraggedSize)) + 1) - / 2; - } - scrubberScale = 1.0f; - scrubberScalingAnimator = new ValueAnimator(); - scrubberScalingAnimator.addUpdateListener( - animation -> { - scrubberScale = (float) animation.getAnimatedValue(); - invalidate(seekBounds); - }); - duration = C.TIME_UNSET; - keyTimeIncrement = C.TIME_UNSET; - keyCountIncrement = DEFAULT_INCREMENT_COUNT; - setFocusable(true); - if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); - } - } - - public void setThumbnailUtils(ThumbnailProvider thumbnailUtils) { - this.thumbnailUtils = thumbnailUtils; - } - - /** Shows the scrubber handle. */ - public void showScrubber() { - if (scrubberScalingAnimator.isStarted()) { - scrubberScalingAnimator.cancel(); - } - scrubberPaddingDisabled = false; - scrubberScale = 1; - invalidate(seekBounds); - } - - /** - * Shows the scrubber handle with animation. - * - * @param showAnimationDurationMs The duration for scrubber showing animation. - */ - public void showScrubber(long showAnimationDurationMs) { - if (scrubberScalingAnimator.isStarted()) { - scrubberScalingAnimator.cancel(); - } - scrubberPaddingDisabled = false; - scrubberScalingAnimator.setFloatValues(scrubberScale, SHOWN_SCRUBBER_SCALE); - scrubberScalingAnimator.setDuration(showAnimationDurationMs); - scrubberScalingAnimator.start(); - } - - /** Hides the scrubber handle. */ - public void hideScrubber(boolean disableScrubberPadding) { - if (scrubberScalingAnimator.isStarted()) { - scrubberScalingAnimator.cancel(); - } - scrubberPaddingDisabled = disableScrubberPadding; - scrubberScale = 0; - invalidate(seekBounds); - } - - /** - * Hides the scrubber handle with animation. - * - * @param hideAnimationDurationMs The duration for scrubber hiding animation. - */ - public void hideScrubber(long hideAnimationDurationMs) { - if (scrubberScalingAnimator.isStarted()) { - scrubberScalingAnimator.cancel(); - } - scrubberScalingAnimator.setFloatValues(scrubberScale, HIDDEN_SCRUBBER_SCALE); - scrubberScalingAnimator.setDuration(hideAnimationDurationMs); - scrubberScalingAnimator.start(); - } - - /** - * Sets the color for the portion of the time bar representing media before the playback position. - * - * @param playedColor The color for the portion of the time bar representing media before the - * playback position. - */ - public void setPlayedColor(@ColorInt int playedColor) { - playedPaint.setColor(playedColor); - invalidate(seekBounds); - } - - /** - * Sets the color for the scrubber handle. - * - * @param scrubberColor The color for the scrubber handle. - */ - public void setScrubberColor(@ColorInt int scrubberColor) { - scrubberPaint.setColor(scrubberColor); - invalidate(seekBounds); - } - - /** - * Sets the color for the portion of the time bar after the current played position up to the - * current buffered position. - * - * @param bufferedColor The color for the portion of the time bar after the current played - * position up to the current buffered position. - */ - public void setBufferedColor(@ColorInt int bufferedColor) { - bufferedPaint.setColor(bufferedColor); - invalidate(seekBounds); - } - - /** - * Sets the color for the portion of the time bar after the current played position. - * - * @param unplayedColor The color for the portion of the time bar after the current played - * position. - */ - public void setUnplayedColor(@ColorInt int unplayedColor) { - unplayedPaint.setColor(unplayedColor); - invalidate(seekBounds); - } - - /** - * Sets the color for unplayed ad markers. - * - * @param adMarkerColor The color for unplayed ad markers. - */ - public void setAdMarkerColor(@ColorInt int adMarkerColor) { - adMarkerPaint.setColor(adMarkerColor); - invalidate(seekBounds); - } - - /** - * Sets the color for played ad markers. - * - * @param playedAdMarkerColor The color for played ad markers. - */ - public void setPlayedAdMarkerColor(@ColorInt int playedAdMarkerColor) { - playedAdMarkerPaint.setColor(playedAdMarkerColor); - invalidate(seekBounds); - } - - // TimeBar implementation. - - @Override - public void addListener(OnScrubListener listener) { - Assertions.checkNotNull(listener); - listeners.add(listener); - } - - @Override - public void removeListener(OnScrubListener listener) { - listeners.remove(listener); - } - - @Override - public void setKeyTimeIncrement(long time) { - Assertions.checkArgument(time > 0); - keyCountIncrement = C.INDEX_UNSET; - keyTimeIncrement = time; - } - - @Override - public void setKeyCountIncrement(int count) { - Assertions.checkArgument(count > 0); - keyCountIncrement = count; - keyTimeIncrement = C.TIME_UNSET; - } - - @Override - public void setPosition(long position) { - if (this.position == position) { - return; - } - this.position = position; - setContentDescription(getProgressText()); - update(); - } - - @Override - public void setBufferedPosition(long bufferedPosition) { - if (this.bufferedPosition == bufferedPosition) { - return; - } - this.bufferedPosition = bufferedPosition; - update(); - } - - @Override - public void setDuration(long duration) { - if (this.duration == duration) { - return; - } - this.duration = duration; - if (scrubbing && duration == C.TIME_UNSET) { - stopScrubbing(/* canceled= */ true); - } - update(); - } - - @Override - public long getPreferredUpdateDelay() { - int timeBarWidthDp = pxToDp(density, progressBar.width()); - return timeBarWidthDp == 0 || duration == 0 || duration == C.TIME_UNSET - ? Long.MAX_VALUE - : duration / timeBarWidthDp; - } - - @Override - public void setAdGroupTimesMs( - @Nullable long[] adGroupTimesMs, @Nullable boolean[] playedAdGroups, int adGroupCount) { - Assertions.checkArgument( - adGroupCount == 0 || (adGroupTimesMs != null && playedAdGroups != null)); - this.adGroupCount = adGroupCount; - this.adGroupTimesMs = adGroupTimesMs; - this.playedAdGroups = playedAdGroups; - update(); - } - - // View methods. - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - if (scrubbing && !enabled) { - stopScrubbing(/* canceled= */ true); - } - } - - @Override - public void onDraw(Canvas canvas) { - canvas.save(); - drawTimeBar(canvas); - drawPlayhead(canvas); - canvas.restore(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (!isEnabled() || duration <= 0) { - return false; - } - Point touchPosition = resolveRelativeTouchPosition(event); - int x = touchPosition.x; - int y = touchPosition.y; - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - if (isInSeekBar(x, y)) { - positionScrubber(x); - startScrubbing(getScrubberPosition()); - update(); - invalidate(); - return true; - } - break; - case MotionEvent.ACTION_MOVE: - if (scrubbing) { - if (y < fineScrubYThreshold) { - int relativeX = x - lastCoarseScrubXPosition; - positionScrubber(lastCoarseScrubXPosition + relativeX / FINE_SCRUB_RATIO); - } else { - lastCoarseScrubXPosition = x; - positionScrubber(x); - } - updateScrubbing(getScrubberPosition()); - update(); - invalidate(); - return true; - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - if (scrubbing) { - stopScrubbing(/* canceled= */ event.getAction() == MotionEvent.ACTION_CANCEL); - return true; - } - break; - default: - // Do nothing. - } - return false; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (isEnabled()) { - long positionIncrement = getPositionIncrement(); - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - positionIncrement = -positionIncrement; - // Fall through. - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (scrubIncrementally(positionIncrement)) { - removeCallbacks(stopScrubbingRunnable); - postDelayed(stopScrubbingRunnable, STOP_SCRUBBING_TIMEOUT_MS); - return true; - } - break; - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: - if (scrubbing) { - stopScrubbing(/* canceled= */ false); - return true; - } - break; - default: - // Do nothing. - } - } - return super.onKeyDown(keyCode, event); - } - - @Override - protected void onFocusChanged( - boolean gainFocus, int direction, @Nullable Rect previouslyFocusedRect) { - super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); - if (scrubbing && !gainFocus) { - stopScrubbing(/* canceled= */ false); - } - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - updateDrawableState(); - } - - @Override - public void jumpDrawablesToCurrentState() { - super.jumpDrawablesToCurrentState(); - if (scrubberDrawable != null) { - scrubberDrawable.jumpToCurrentState(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - int height = - heightMode == MeasureSpec.UNSPECIFIED - ? touchTargetHeight - : heightMode == MeasureSpec.EXACTLY - ? heightSize - : Math.min(touchTargetHeight, heightSize); - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height); - updateDrawableState(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int width = right - left; - int height = bottom - top; - int seekLeft = getPaddingLeft(); - int seekRight = width - getPaddingRight(); - int seekBoundsY; - int progressBarY; - int scrubberPadding = scrubberPaddingDisabled ? 0 : this.scrubberPadding; - if (barGravity == BAR_GRAVITY_BOTTOM) { - seekBoundsY = height - getPaddingBottom() - touchTargetHeight; - progressBarY = - height - getPaddingBottom() - barHeight - Math.max(scrubberPadding - (barHeight / 2), 0); - } else { - seekBoundsY = (height - touchTargetHeight) / 2; - progressBarY = (height - barHeight) / 2; - } - seekBounds.set(seekLeft, seekBoundsY, seekRight, seekBoundsY + touchTargetHeight); - progressBar.set( - seekBounds.left + scrubberPadding, - progressBarY, - seekBounds.right - scrubberPadding, - progressBarY + barHeight); - if (Util.SDK_INT >= 29) { - setSystemGestureExclusionRectsV29(width, height); - } - update(); - } - - @Override - public void onRtlPropertiesChanged(int layoutDirection) { - if (scrubberDrawable != null && setDrawableLayoutDirection(scrubberDrawable, layoutDirection)) { - invalidate(); - } - } - - @Override - public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SELECTED) { - event.getText().add(getProgressText()); - } - event.setClassName(ACCESSIBILITY_CLASS_NAME); - } - - @Override - public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - info.setClassName(ACCESSIBILITY_CLASS_NAME); - info.setContentDescription(getProgressText()); - if (duration <= 0) { - return; - } - if (Util.SDK_INT >= 21) { - info.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD); - info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD); - } else { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); - } - } - - @Override - public boolean performAccessibilityAction(int action, @Nullable Bundle args) { - if (super.performAccessibilityAction(action, args)) { - return true; - } - if (duration <= 0) { - return false; - } - if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) { - if (scrubIncrementally(-getPositionIncrement())) { - stopScrubbing(/* canceled= */ false); - } - } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) { - if (scrubIncrementally(getPositionIncrement())) { - stopScrubbing(/* canceled= */ false); - } - } else { - return false; - } - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); - return true; - } - - // Internal methods. - - private void startScrubbing(long scrubPosition) { - this.scrubPosition = scrubPosition; - scrubbing = true; - setPressed(true); - ViewParent parent = getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - for (OnScrubListener listener : listeners) { - listener.onScrubStart(this, scrubPosition); - } - } - - private void updateScrubbing(long scrubPosition) { - if (this.scrubPosition == scrubPosition) { - return; - } - this.scrubPosition = scrubPosition; - for (OnScrubListener listener : listeners) { - listener.onScrubMove(this, scrubPosition); - } - } - - private void stopScrubbing(boolean canceled) { - removeCallbacks(stopScrubbingRunnable); - scrubbing = false; - setPressed(false); - ViewParent parent = getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(false); - } - invalidate(); - for (OnScrubListener listener : listeners) { - listener.onScrubStop(this, scrubPosition, canceled); - } - } - - /** - * Incrementally scrubs the position by {@code positionChange}. - * - * @param positionChange The change in the scrubber position, in milliseconds. May be negative. - * @return Returns whether the scrubber position changed. - */ - private boolean scrubIncrementally(long positionChange) { - if (duration <= 0) { - return false; - } - long previousPosition = scrubbing ? scrubPosition : position; - long scrubPosition = Util.constrainValue(previousPosition + positionChange, 0, duration); - if (scrubPosition == previousPosition) { - return false; - } - if (!scrubbing) { - startScrubbing(scrubPosition); - } else { - updateScrubbing(scrubPosition); - } - update(); - return true; - } - - private void update() { - bufferedBar.set(progressBar); - scrubberBar.set(progressBar); - long newScrubberTime = scrubbing ? scrubPosition : position; - if (duration > 0) { - int bufferedPixelWidth = (int) ((progressBar.width() * bufferedPosition) / duration); - bufferedBar.right = Math.min(progressBar.left + bufferedPixelWidth, progressBar.right); - int scrubberPixelPosition = (int) ((progressBar.width() * newScrubberTime) / duration); - scrubberBar.right = Math.min(progressBar.left + scrubberPixelPosition, progressBar.right); - } else { - bufferedBar.right = progressBar.left; - scrubberBar.right = progressBar.left; - } - invalidate(seekBounds); - } - - private void positionScrubber(float xPosition) { - scrubberBar.right = Util.constrainValue((int) xPosition, progressBar.left, progressBar.right); - } - - private Point resolveRelativeTouchPosition(MotionEvent motionEvent) { - touchPosition.set((int) motionEvent.getX(), (int) motionEvent.getY()); - return touchPosition; - } - - private long getScrubberPosition() { - if (progressBar.width() <= 0 || duration == C.TIME_UNSET) { - return 0; - } - return (scrubberBar.width() * duration) / progressBar.width(); - } - - private boolean isInSeekBar(float x, float y) { - return seekBounds.contains((int) x, (int) y); - } - - private void drawTimeBar(Canvas canvas) { - int progressBarHeight = progressBar.height(); - int barTop = progressBar.centerY() - progressBarHeight / 2; - int barBottom = barTop + progressBarHeight; - if (duration <= 0) { - canvas.drawRect(progressBar.left, barTop, progressBar.right, barBottom, unplayedPaint); - return; - } - int bufferedLeft = bufferedBar.left; - int bufferedRight = bufferedBar.right; - int progressLeft = Math.max(Math.max(progressBar.left, bufferedRight), scrubberBar.right); - if (progressLeft < progressBar.right) { - canvas.drawRect(progressLeft, barTop, progressBar.right, barBottom, unplayedPaint); - } - bufferedLeft = Math.max(bufferedLeft, scrubberBar.right); - if (bufferedRight > bufferedLeft) { - canvas.drawRect(bufferedLeft, barTop, bufferedRight, barBottom, bufferedPaint); - } - if (scrubberBar.width() > 0) { - canvas.drawRect(scrubberBar.left, barTop, scrubberBar.right, barBottom, playedPaint); - } - if (adGroupCount == 0) { - return; - } - long[] adGroupTimesMs = Assertions.checkNotNull(this.adGroupTimesMs); - boolean[] playedAdGroups = Assertions.checkNotNull(this.playedAdGroups); - int adMarkerOffset = adMarkerWidth / 2; - for (int i = 0; i < adGroupCount; i++) { - long adGroupTimeMs = Util.constrainValue(adGroupTimesMs[i], 0, duration); - int markerPositionOffset = - (int) (progressBar.width() * adGroupTimeMs / duration) - adMarkerOffset; - int markerLeft = - progressBar.left - + Math.min(progressBar.width() - adMarkerWidth, Math.max(0, markerPositionOffset)); - Paint paint = playedAdGroups[i] ? playedAdMarkerPaint : adMarkerPaint; - canvas.drawRect(markerLeft, barTop, markerLeft + adMarkerWidth, barBottom, paint); - } - } - - private void drawPlayhead(Canvas canvas) { - if (duration <= 0) { - return; - } - int playheadX = Util.constrainValue(scrubberBar.right, scrubberBar.left, progressBar.right); - int playheadY = scrubberBar.centerY(); - if (scrubberDrawable == null) { - int scrubberSize = - (scrubbing || isFocused()) - ? scrubberDraggedSize - : (isEnabled() ? scrubberEnabledSize : scrubberDisabledSize); - int playheadRadius = (int) ((scrubberSize * scrubberScale) / 2); - canvas.drawCircle(playheadX, playheadY, playheadRadius, scrubberPaint); - - if (scrubbing) drawThumbnail(canvas, playheadRadius, playheadX, playheadY); - } else { - int scrubberDrawableWidth = (int) (scrubberDrawable.getIntrinsicWidth() * scrubberScale); - int scrubberDrawableHeight = (int) (scrubberDrawable.getIntrinsicHeight() * scrubberScale); - scrubberDrawable.setBounds( - playheadX - scrubberDrawableWidth / 2, - playheadY - scrubberDrawableHeight / 2, - playheadX + scrubberDrawableWidth / 2, - playheadY + scrubberDrawableHeight / 2); - scrubberDrawable.draw(canvas); - } - } - - private void drawThumbnail(Canvas canvas, int playheadRadius, int playheadX, int playheadY) { - - if (thumbnailUtils == null) return; - Bitmap b = thumbnailUtils.getThumbnail(getScrubberPosition()); - - if (b == null) return; - - //adapt thumbnail to desired UI size - double arFactor = (double) b.getWidth() / b.getHeight(); - b = Bitmap.createScaledBitmap(b, dpToPx((int)(targetThumbnailHeightInDp * arFactor)), dpToPx(targetThumbnailHeightInDp), false); - - int width = b.getWidth(); - int height = b.getHeight(); - int offset = (int)width / 2; - - int left = playheadX-offset; - - //handle full left, full right position cases - if (left < 0 ) left = 0; - if (left + width > progressBar.width() + playheadRadius) left = progressBar.width() + playheadRadius - width; - - canvas.drawBitmap(b, left, playheadY-playheadRadius*2-height, null); - } - - private int dpToPx(int dp){ - return (int) (dp * getContext().getResources().getDisplayMetrics().density); - } - - private void updateDrawableState() { - if (scrubberDrawable != null - && scrubberDrawable.isStateful() - && scrubberDrawable.setState(getDrawableState())) { - invalidate(); - } - } - - @RequiresApi(29) - private void setSystemGestureExclusionRectsV29(int width, int height) { - if (lastExclusionRectangle != null - && lastExclusionRectangle.width() == width - && lastExclusionRectangle.height() == height) { - // Allocating inside onLayout is considered a DrawAllocation lint error, so avoid if possible. - return; - } - lastExclusionRectangle = new Rect(/* left= */ 0, /* top= */ 0, width, height); - setSystemGestureExclusionRects(Collections.singletonList(lastExclusionRectangle)); - } - - private String getProgressText() { - return Util.getStringForTime(formatBuilder, formatter, position); - } - - private long getPositionIncrement() { - return keyTimeIncrement == C.TIME_UNSET - ? (duration == C.TIME_UNSET ? 0 : (duration / keyCountIncrement)) - : keyTimeIncrement; - } - - private boolean setDrawableLayoutDirection(Drawable drawable) { - return Util.SDK_INT >= 23 && setDrawableLayoutDirection(drawable, getLayoutDirection()); - } - - private static boolean setDrawableLayoutDirection(Drawable drawable, int layoutDirection) { - return Util.SDK_INT >= 23 && drawable.setLayoutDirection(layoutDirection); - } - - private static int dpToPx(float density, int dps) { - return (int) (dps * density + 0.5f); - } - - private static int pxToDp(float density, int px) { - return (int) (px / density); - } -} diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index d7b381baf0..ae01315f12 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -75,7 +75,6 @@ public class PlayerActivity extends AppCompatActivity protected LinearLayout debugRootView; protected TextView debugTextView; protected @Nullable ExoPlayer player; - DefaultThumbnailTimeBar timeBar; private boolean isShowingTrackSelectionDialog; private Button selectTracksButton; @@ -117,9 +116,6 @@ public class PlayerActivity extends AppCompatActivity playerView.setControllerVisibilityListener(this); playerView.setErrorMessageProvider(new PlayerErrorMessageProvider()); playerView.requestFocus(); - - timeBar = playerView.findViewById(R.id.exo_progress); - if (savedInstanceState != null) { trackSelectionParameters = TrackSelectionParameters.fromBundle( @@ -285,7 +281,7 @@ public class PlayerActivity extends AppCompatActivity player.setPlayWhenReady(startAutoPlay); playerView.setPlayer(player); configurePlayerWithServerSideAdsLoader(); - timeBar.setThumbnailUtils(new DefaultThumbnailProvider(player, timeBar)); + debugViewHelper = new DebugTextViewHelper(player, debugTextView); debugViewHelper.start(); } diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/ThumbnailProvider.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/ThumbnailProvider.java deleted file mode 100644 index 129fc84b16..0000000000 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/ThumbnailProvider.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.google.android.exoplayer2.demo; - -import android.graphics.Bitmap; - -public interface ThumbnailProvider { - - public Bitmap getThumbnail(long position); - -} diff --git a/demos/main/src/main/res/layout/exo_styled_player_control_view.xml b/demos/main/src/main/res/layout/exo_styled_player_control_view.xml deleted file mode 100644 index 2a6ae481da..0000000000 --- a/demos/main/src/main/res/layout/exo_styled_player_control_view.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java b/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java index cfd1f6e8fe..2323449fb8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java @@ -1,11 +1,12 @@ package com.google.android.exoplayer2.thumbnail; import android.net.Uri; +import androidx.annotation.NonNull; public class ThumbnailDescription { - private final String id; - private final Uri uri; + @NonNull private final String id; + @NonNull private final Uri uri; private final int bitrate; private final int tileCountHorizontal; private final int tileCountVertical; @@ -14,7 +15,7 @@ public class ThumbnailDescription { private final int imageWidth; // Image width (Pixel) private final int imageHeight; // Image height (Pixel) - public ThumbnailDescription(String id, Uri uri, int bitrate, int tileCountHorizontal, int tileCountVertical, long startTimeMs, long durationMs, int imageWidth, int imageHeight) { + public ThumbnailDescription(@NonNull String id, @NonNull Uri uri, int bitrate, int tileCountHorizontal, int tileCountVertical, long startTimeMs, long durationMs, int imageWidth, int imageHeight) { this.id = id; this.uri = uri; this.bitrate = bitrate; @@ -26,6 +27,12 @@ public class ThumbnailDescription { this.imageHeight = imageHeight; } + @NonNull + public String getId() { + return id; + } + + @NonNull public Uri getUri() { return uri; } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java index e44306a17e..2ea76b944d 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java @@ -182,6 +182,9 @@ public class DashManifest implements FilterableManifest { } String id = representation.format.id; + if (id == null) { + continue; + } int bitrate = representation.format.bitrate; int imageWidth = representation.format.width; int imageHeight = representation.format.height;