1/*
2 * Copyright (C) 2017 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.incallui.answer.impl;
18
19import android.content.Context;
20import android.content.res.TypedArray;
21import android.util.AttributeSet;
22import android.view.SurfaceView;
23import android.view.View;
24import com.android.dialer.common.Assert;
25
26/**
27 * A SurfaceView that maintains its aspect ratio to be a desired target value.
28 *
29 * <p>The FixedAspectSurfaceView will not be able to maintain the requested aspect ratio if both the
30 * width and the height are exactly determined by the layout. To avoid this, ensure that either the
31 * height or the width is adjustable by the view; for example, by setting the layout parameters to
32 * be WRAP_CONTENT for the dimension that is best adjusted to maintain the aspect ratio.
33 */
34public class FixedAspectSurfaceView extends SurfaceView {
35
36  /** Desired width/height ratio */
37  private float mAspectRatio;
38
39  private final boolean scaleWidth;
40  private final boolean scaleHeight;
41
42  public FixedAspectSurfaceView(Context context, AttributeSet attrs) {
43    super(context, attrs);
44
45    // Get initial aspect ratio from custom attributes
46    TypedArray a =
47        context.getTheme().obtainStyledAttributes(attrs, R.styleable.FixedAspectSurfaceView, 0, 0);
48    scaleHeight = a.getBoolean(R.styleable.FixedAspectSurfaceView_scaleHeight, false);
49    scaleWidth = a.getBoolean(R.styleable.FixedAspectSurfaceView_scaleWidth, false);
50    Assert.checkArgument(scaleHeight != scaleWidth, "Must either scale width or height");
51    setAspectRatio(a.getFloat(R.styleable.FixedAspectSurfaceView_aspectRatio, 1.f));
52    a.recycle();
53  }
54
55  /**
56   * Set the desired aspect ratio for this view.
57   *
58   * @param aspect the desired width/height ratio in the current UI orientation. Must be a positive
59   *     value.
60   */
61  public void setAspectRatio(float aspect) {
62    Assert.checkArgument(aspect >= 0, "Aspect ratio must be positive");
63    mAspectRatio = aspect;
64    requestLayout();
65  }
66
67  @Override
68  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
69    int width = MeasureSpec.getSize(widthMeasureSpec);
70    int height = MeasureSpec.getSize(heightMeasureSpec);
71
72    // Do the scaling
73    if (scaleWidth) {
74      width = (int) (height * mAspectRatio);
75    } else if (scaleHeight) {
76      height = (int) (width / mAspectRatio);
77    }
78
79    // Override width/height if needed for EXACTLY and AT_MOST specs
80    width = View.resolveSizeAndState(width, widthMeasureSpec, 0);
81    height = View.resolveSizeAndState(height, heightMeasureSpec, 0);
82
83    // Finally set the calculated dimensions
84    setMeasuredDimension(width, height);
85  }
86}
87