110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng/*
210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Copyright (C) 2012 The Android Open Source Project
310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng *
410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * you may not use this file except in compliance with the License.
610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * You may obtain a copy of the License at
710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng *
810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng *
1010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Unless required by applicable law or agreed to in writing, software
1110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
1210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * See the License for the specific language governing permissions and
1410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * limitations under the License.
1510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng */
1610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
1710392a75b43c34be8580a9fa101062201ce441d6Chiao Chengpackage com.android.contacts.common.widget;
1810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
1910392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.content.Context;
2010392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.content.res.TypedArray;
2110392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.util.AttributeSet;
2210392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.view.View;
2310392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.view.ViewGroup;
2410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
25baefde748cd02bde8934d66c34b3e1067745771dChiao Chengimport com.android.contacts.common.R;
2610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
2710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng/**
2810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Layout that calculates its height based on its width, or vice versa (depending on the set
2910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * {@link #setDirection(Direction)}. The factor is specified in {@link #setRatio(float)}.
3010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * <p>For {@link Direction#heightToWidth}: width := height * factor</p>
3110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * <p>For {@link Direction#widthToHeight}: height := width * factor</p>
3210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * <p>Only one child is allowed; if more are required, another ViewGroup can be used as the direct
3310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * child of this layout.</p>
3410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng */
3510392a75b43c34be8580a9fa101062201ce441d6Chiao Chengpublic class ProportionalLayout extends ViewGroup {
3610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    /** Specifies whether the width should be calculated based on the height or vice-versa  */
3710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public enum Direction {
3810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        widthToHeight("widthToHeight"),
3910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        heightToWidth("heightToWidth");
4010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
4110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        public final String XmlName;
4210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
4310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        private Direction(String xmlName) {
4410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            XmlName = xmlName;
4510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        }
4610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
4710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        /**
4810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng         * Parses the given direction string and returns the Direction instance. This
4910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng         * should be used when inflating from xml
5010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng         */
5110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        public static Direction parse(String value) {
5210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            if (widthToHeight.XmlName.equals(value)) {
5310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng                return Direction.widthToHeight;
5410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            } else if (heightToWidth.XmlName.equals(value)) {
5510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng                return Direction.heightToWidth;
5610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            } else {
5710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng                throw new IllegalStateException("direction must be either " +
5810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng                        widthToHeight.XmlName + " or " + heightToWidth.XmlName);
5910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            }
6010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        }
6110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
6210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
6310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    private Direction mDirection;
6410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    private float mRatio;
6510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
6610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public ProportionalLayout(Context context) {
6710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        super(context);
6810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
6910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
7010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public ProportionalLayout(Context context, AttributeSet attrs) {
7110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        super(context, attrs);
7210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        initFromAttributes(context, attrs);
7310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
7410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
7510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public ProportionalLayout(Context context, AttributeSet attrs, int defStyle) {
7610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        super(context, attrs, defStyle);
7710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        initFromAttributes(context, attrs);
7810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
7910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
8010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    private void initFromAttributes(Context context, AttributeSet attrs) {
8110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProportionalLayout);
8210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
8310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        mDirection = Direction.parse(a.getString(R.styleable.ProportionalLayout_direction));
8410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        mRatio = a.getFloat(R.styleable.ProportionalLayout_ratio, 1.0f);
8510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
8610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        a.recycle();
8710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
8810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
8910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    @Override
9010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
9110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        if (getChildCount() != 1) {
9210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            throw new IllegalStateException("ProportionalLayout requires exactly one child");
9310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        }
9410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
9510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        final View child = getChildAt(0);
9610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
9710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        // Do a first pass to get the optimal size
9810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        measureChild(child, widthMeasureSpec, heightMeasureSpec);
9910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        final int childWidth = child.getMeasuredWidth();
10010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        final int childHeight = child.getMeasuredHeight();
10110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
10210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        final int width;
10310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        final int height;
10410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        if (mDirection == Direction.heightToWidth) {
10510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            width = Math.round(childHeight * mRatio);
10610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            height = childHeight;
10710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        } else {
10810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            width = childWidth;
10910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            height = Math.round(childWidth * mRatio);
11010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        }
11110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
11210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        // Do a second pass so that all children are informed of the new size
11310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        measureChild(child,
11410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng                MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
11510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
11610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
11710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        setMeasuredDimension(
11810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng                resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));
11910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
12010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
12110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    @Override
12210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
12310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        if (getChildCount() != 1) {
12410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng            throw new IllegalStateException("ProportionalLayout requires exactly one child");
12510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        }
12610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
12710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        final View child = getChildAt(0);
12810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        child.layout(0, 0, right-left, bottom-top);
12910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
13010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
13110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public Direction getDirection() {
13210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        return mDirection;
13310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
13410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
13510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public void setDirection(Direction direction) {
13610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        mDirection = direction;
13710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
13810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
13910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public float getRatio() {
14010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        return mRatio;
14110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
14210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng
14310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    public void setRatio(float ratio) {
14410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng        mRatio = ratio;
14510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng    }
14610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng}
147