// started from https://github.com/google/grafika/blob/f3c8c3dee60153f471312e21acac8b3a3cddd7dc/src/com/android/grafika/AspectFrameLayout.java /* * Copyright 2014 Google Inc. All rights reserved. * * 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 io.cine.android.streaming; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.FrameLayout; /** * Layout that adjusts to maintain a specific aspect ratio. */ public class AspectFrameLayout extends FrameLayout { private static final String TAG = "AspectFrameLayout"; private double mTargetAspect = -1.0; // initially use default window size public AspectFrameLayout(Context context) { super(context); } public AspectFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } /** * Sets the desired aspect ratio. The value is <code>width / height</code>. */ public void setAspectRatio(double aspectRatio) { if (aspectRatio < 0) { throw new IllegalArgumentException(); } Log.d(TAG, "Setting aspect ratio to " + aspectRatio + " (was " + mTargetAspect + ")"); if (mTargetAspect != aspectRatio) { mTargetAspect = aspectRatio; requestLayout(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.d(TAG, "onMeasure target=" + mTargetAspect + " width=[" + MeasureSpec.toString(widthMeasureSpec) + "] height=[" + View.MeasureSpec.toString(heightMeasureSpec) + "]"); // Target aspect ratio will be < 0 if it hasn't been set yet. In that case, // we just use whatever we've been handed. if (mTargetAspect > 0) { int initialWidth = MeasureSpec.getSize(widthMeasureSpec); int initialHeight = MeasureSpec.getSize(heightMeasureSpec); // factor the padding out int horizPadding = getPaddingLeft() + getPaddingRight(); int vertPadding = getPaddingTop() + getPaddingBottom(); initialWidth -= horizPadding; initialHeight -= vertPadding; double viewAspectRatio = (double) initialWidth / initialHeight; double aspectDiff = mTargetAspect / viewAspectRatio - 1; if (Math.abs(aspectDiff) < 0.01) { // We're very close already. We don't want to risk switching from e.g. non-scaled // 1280x720 to scaled 1280x719 because of some floating-point round-off error, // so if we're really close just leave it alone. Log.d(TAG, "aspect ratio is good (target=" + mTargetAspect + ", view=" + initialWidth + "x" + initialHeight + ")"); } else { if (aspectDiff > 0) { // limited by narrow width; restrict height initialHeight = (int) (initialWidth / mTargetAspect); } else { // limited by short height; restrict width initialWidth = (int) (initialHeight * mTargetAspect); } Log.d(TAG, "new size=" + initialWidth + "x" + initialHeight + " + padding " + horizPadding + "x" + vertPadding); initialWidth += horizPadding; initialHeight += vertPadding; widthMeasureSpec = MeasureSpec.makeMeasureSpec(initialWidth, MeasureSpec.EXACTLY); heightMeasureSpec = MeasureSpec.makeMeasureSpec(initialHeight, MeasureSpec.EXACTLY); } } //Log.d(TAG, "set width=[" + MeasureSpec.toString(widthMeasureSpec) + // "] height=[" + View.MeasureSpec.toString(heightMeasureSpec) + "]"); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }