Skip to content

Commit

Permalink
Add support for listening to AspectRatioFrameLayout's aspect ratio up…
Browse files Browse the repository at this point in the history
…date

Currently, AspectRatioFrameLayout may need to resize itself if it could not
satisfy a target aspect ratio. User may want to know when this happen, or
whether this can happen, so they can update their UI accordingly. For
example: show/hide a button to toggle different resize mode only when the
aspect ratio of the view and the content is very different.

GitHub: #3736

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=187484241
  • Loading branch information
botaydotcom authored and andrewlewis committed Mar 2, 2018
1 parent fdfaa02 commit a3c8062
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 3 deletions.
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

### dev-v2 (not yet released) ###

* UI components:
* Add support for listening to `AspectRatioFrameLayout`'s aspect ratio update
([#3736](https://github.com/google/ExoPlayer/issues/3736)).
* Gradle: Replace 'compile' configuration (deprecated) with 'implementation' and
'api'. Note: This may lead to build breakage for applications upgrading from
previous version that rely on indirect dependency for certain modules. In such
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@
*/
public final class AspectRatioFrameLayout extends FrameLayout {

/** Listener to be notified about changes of the aspect ratios of this view. */
public interface AspectRatioListener {

/**
* Called when either the target aspect ratio or the view aspect ratio is updated.
*
* @param targetAspectRatio The aspect ratio that has been set in {@link #setAspectRatio(float)}
* @param naturalAspectRatio The natural aspect ratio of this view (before its width and height
* are modified to satisfy the target aspect ratio).
* @param aspectRatioMismatch Whether the target and natural aspect ratios differ enough for
* changing the resize mode to have an effect.
*/
void onAspectRatioUpdated(
float targetAspectRatio, float naturalAspectRatio, boolean aspectRatioMismatch);
}

// LINT.IfChange
/** Resize modes for {@link AspectRatioFrameLayout}. */
@Retention(RetentionPolicy.SOURCE)
Expand Down Expand Up @@ -73,8 +89,12 @@ public final class AspectRatioFrameLayout extends FrameLayout {
*/
private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f;

private final AspectRatioUpdateDispatcher aspectRatioUpdateDispatcher;

private AspectRatioListener aspectRatioListener;

private float videoAspectRatio;
private int resizeMode;
private @ResizeMode int resizeMode;

public AspectRatioFrameLayout(Context context) {
this(context, null);
Expand All @@ -92,6 +112,7 @@ public AspectRatioFrameLayout(Context context, AttributeSet attrs) {
a.recycle();
}
}
aspectRatioUpdateDispatcher = new AspectRatioUpdateDispatcher();
}

/**
Expand All @@ -106,6 +127,15 @@ public void setAspectRatio(float widthHeightRatio) {
}
}

/**
* Sets the {@link AspectRatioListener}.
*
* @param listener The listener to be notified about aspect ratios changes.
*/
public void setAspectRatioListener(AspectRatioListener listener) {
this.aspectRatioListener = listener;
}

/**
* Returns the resize mode.
*/
Expand All @@ -128,7 +158,7 @@ public void setResizeMode(@ResizeMode int resizeMode) {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (resizeMode == RESIZE_MODE_FILL || videoAspectRatio <= 0) {
if (videoAspectRatio <= 0) {
// Aspect ratio not set.
return;
}
Expand All @@ -139,6 +169,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) {
// We're within the allowed tolerance.
aspectRatioUpdateDispatcher.scheduleUpdate(videoAspectRatio, viewAspectRatio, false);
return;
}

Expand All @@ -156,16 +187,51 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
height = (int) (width / videoAspectRatio);
}
break;
default:
case RESIZE_MODE_FIT:
if (aspectDeformation > 0) {
height = (int) (width / videoAspectRatio);
} else {
width = (int) (height * videoAspectRatio);
}
break;
case RESIZE_MODE_FILL:
default:
// Ignore target aspect ratio
break;
}
aspectRatioUpdateDispatcher.scheduleUpdate(videoAspectRatio, viewAspectRatio, true);
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}

/** Dispatches updates to {@link AspectRatioListener}. */
private final class AspectRatioUpdateDispatcher implements Runnable {

private float targetAspectRatio;
private float naturalAspectRatio;
private boolean aspectRatioMismatch;
private boolean isScheduled;

public void scheduleUpdate(
float targetAspectRatio, float naturalAspectRatio, boolean aspectRatioMismatch) {
this.targetAspectRatio = targetAspectRatio;
this.naturalAspectRatio = naturalAspectRatio;
this.aspectRatioMismatch = aspectRatioMismatch;

if (!isScheduled) {
isScheduled = true;
post(this);
}
}

@Override
public void run() {
isScheduled = false;
if (aspectRatioListener == null) {
return;
}
aspectRatioListener.onAspectRatioUpdated(
targetAspectRatio, naturalAspectRatio, aspectRatioMismatch);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,12 @@ public void setResizeMode(@ResizeMode int resizeMode) {
contentFrame.setResizeMode(resizeMode);
}

/** Returns the resize mode. */
public @ResizeMode int getResizeMode() {
Assertions.checkState(contentFrame != null);
return contentFrame.getResizeMode();
}

/** Returns whether artwork is displayed if present in the media. */
public boolean getUseArtwork() {
return useArtwork;
Expand Down Expand Up @@ -750,6 +756,17 @@ public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
controller.setShowMultiWindowTimeBar(showMultiWindowTimeBar);
}

/**
* Set the {@link AspectRatioFrameLayout.AspectRatioListener}.
*
* @param listener The listener to be notified about aspect ratios changes of the video content or
* the content frame.
*/
public void setAspectRatioListener(AspectRatioFrameLayout.AspectRatioListener listener) {
Assertions.checkState(contentFrame != null);
contentFrame.setAspectRatioListener(listener);
}

/**
* Gets the view onto which video is rendered. This is a:
*
Expand Down

0 comments on commit a3c8062

Please sign in to comment.