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 
17 package com.android.incallui.answer.impl;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.util.AttributeSet;
22 import android.view.SurfaceView;
23 import android.view.View;
24 import 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  */
34 public 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 
FixedAspectSurfaceView(Context context, AttributeSet attrs)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    */
setAspectRatio(float aspect)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
onMeasure(int widthMeasureSpec, int heightMeasureSpec)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