From 749d77b1d9989d091dc11269087093bc2c48d216 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 30 Nov 2022 18:54:31 +0000 Subject: [PATCH] Make PlayerView fold aware PiperOrigin-RevId: 491963883 --- constants.gradle | 1 + library/ui/build.gradle | 2 + .../exoplayer2/ui/StyledPlayerView.java | 84 +++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/constants.gradle b/constants.gradle index 3068e7646b..3840bb533f 100644 --- a/constants.gradle +++ b/constants.gradle @@ -54,6 +54,7 @@ project.ext { androidxTestRulesVersion = '1.4.0' androidxTestServicesStorageVersion = '1.4.0' androidxTestTruthVersion = '1.4.0' + androidxWindowVersion = '1.0.0' truthVersion = '1.1.3' okhttpVersion = '4.9.2' modulePrefix = ':' diff --git a/library/ui/build.gradle b/library/ui/build.gradle index 7b21db436e..c7c990069d 100644 --- a/library/ui/build.gradle +++ b/library/ui/build.gradle @@ -25,7 +25,9 @@ dependencies { implementation project(modulePrefix + 'library-common') api 'androidx.media:media:' + androidxMediaVersion implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion + implementation 'androidx.core:core:' + androidxCoreVersion implementation 'androidx.recyclerview:recyclerview:' + androidxRecyclerViewVersion + implementation 'androidx.window:window:' + androidxWindowVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion testImplementation project(modulePrefix + 'testutils') diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java index da17c4c1c7..3f5d2dd28f 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java @@ -21,7 +21,10 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static java.lang.annotation.ElementType.TYPE_USE; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -48,6 +51,14 @@ import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; +import androidx.core.util.Consumer; +import androidx.window.java.layout.WindowInfoTrackerCallbackAdapter; +import androidx.window.layout.DisplayFeature; +import androidx.window.layout.FoldingFeature; +import androidx.window.layout.FoldingFeature.Orientation; +import androidx.window.layout.FoldingFeature.State; +import androidx.window.layout.WindowInfoTracker; +import androidx.window.layout.WindowLayoutInfo; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.PlaybackException; @@ -71,6 +82,7 @@ import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.RequiresNonNull; /** @@ -258,6 +270,9 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { private boolean controllerHideOnTouch; private int textureViewRotation; private boolean isTouching; + private boolean isTabletop; + private final WindowInfoTrackerCallbackAdapter windowInfoTracker; + @MonotonicNonNull private Consumer layoutStateChangeCallback; public StyledPlayerView(Context context) { this(context, /* attrs= */ null); @@ -271,6 +286,9 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { public StyledPlayerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + isTabletop = false; + windowInfoTracker = + new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(context)); componentListener = new ComponentListener(); if (isInEditMode()) { @@ -572,6 +590,25 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { } } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + layoutStateChangeCallback = this::consumeWindowLayoutInfo; + @Nullable Activity activity = getActivity(); + if (activity != null) { + windowInfoTracker.addWindowLayoutInfoListener( + activity, ContextCompat.getMainExecutor(getContext()), layoutStateChangeCallback); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (layoutStateChangeCallback != null) { + windowInfoTracker.removeWindowLayoutInfoListener(layoutStateChangeCallback); + } + } + /** * Sets the {@link ResizeMode}. * @@ -1466,6 +1503,53 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { || keyCode == KeyEvent.KEYCODE_DPAD_CENTER; } + @Nullable + private Activity getActivity() { + Context context = getContext(); + while (context instanceof ContextWrapper) { + if (context instanceof Activity) { + return (Activity) context; + } + context = ((ContextWrapper) context).getBaseContext(); + } + return null; + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + isTabletop = false; + } + + private void consumeWindowLayoutInfo(WindowLayoutInfo windowLayoutInfo) { + List features = windowLayoutInfo.getDisplayFeatures(); + int foldingFeatureIndex = C.INDEX_UNSET; + + for (int i = 0; i < features.size(); i++) { + DisplayFeature feature = features.get(i); + if (feature instanceof FoldingFeature) { + if (foldingFeatureIndex != C.INDEX_UNSET) { + // For now, we are only handling single folding features like tabletop and book fold. + return; + } + foldingFeatureIndex = i; + } + } + if (foldingFeatureIndex != C.INDEX_UNSET) { + handleFoldingFeature((FoldingFeature) features.get(foldingFeatureIndex)); + } + } + + private void handleFoldingFeature(FoldingFeature feature) { + boolean isTabletopFeature = + feature.getOrientation() == Orientation.HORIZONTAL + && feature.getState() == State.HALF_OPENED; + // Only enter or exit tabletop if different than current orientation and state + if (isTabletopFeature != isTabletop) { + isTabletop = isTabletopFeature; + } + } + // Implementing the deprecated StyledPlayerControlView.VisibilityListener and // StyledPlayerControlView.OnFullScreenModeChangedListener for now. @SuppressWarnings("deprecation")