17677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng/*
27677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Copyright (C) 2012 The Android Open Source Project
37677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng *
47677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
57677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * you may not use this file except in compliance with the License.
67677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * You may obtain a copy of the License at
77677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng *
87677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
97677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng *
107677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Unless required by applicable law or agreed to in writing, software
117677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
127677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * See the License for the specific language governing permissions and
147677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * limitations under the License.
157677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng */
167677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1769c182afb0e6d82a341a28b4317aa703af768906Gary Maipackage com.android.contacts.widget;
187677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
197677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.content.Context;
207677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.content.res.TypedArray;
217677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.util.AttributeSet;
227677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.view.View;
237677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.view.ViewGroup;
247677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
253f6a2444e0134b7380cdb2e13abf4bf1163336d0Arthur Wangimport com.android.contacts.R;
267677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
277677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng/**
287677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Layout that calculates its height based on its width, or vice versa (depending on the set
297677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * {@link #setDirection(Direction)}. The factor is specified in {@link #setRatio(float)}.
307677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * <p>For {@link Direction#heightToWidth}: width := height * factor</p>
317677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * <p>For {@link Direction#widthToHeight}: height := width * factor</p>
327677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * <p>Only one child is allowed; if more are required, another ViewGroup can be used as the direct
337677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * child of this layout.</p>
347677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng */
357677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengpublic class ProportionalLayout extends ViewGroup {
367677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    /** Specifies whether the width should be calculated based on the height or vice-versa  */
377677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public enum Direction {
387677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        widthToHeight("widthToHeight"),
397677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        heightToWidth("heightToWidth");
407677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
417677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        public final String XmlName;
427677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
437677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        private Direction(String xmlName) {
447677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            XmlName = xmlName;
457677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        }
467677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
477677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        /**
487677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng         * Parses the given direction string and returns the Direction instance. This
497677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng         * should be used when inflating from xml
507677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng         */
517677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        public static Direction parse(String value) {
527677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            if (widthToHeight.XmlName.equals(value)) {
537677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng                return Direction.widthToHeight;
547677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            } else if (heightToWidth.XmlName.equals(value)) {
557677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng                return Direction.heightToWidth;
567677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            } else {
577677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng                throw new IllegalStateException("direction must be either " +
587677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng                        widthToHeight.XmlName + " or " + heightToWidth.XmlName);
597677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            }
607677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        }
617677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
627677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
637677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    private Direction mDirection;
647677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    private float mRatio;
657677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
667677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public ProportionalLayout(Context context) {
677677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        super(context);
687677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
697677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
707677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public ProportionalLayout(Context context, AttributeSet attrs) {
717677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        super(context, attrs);
727677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        initFromAttributes(context, attrs);
737677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
747677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
757677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public ProportionalLayout(Context context, AttributeSet attrs, int defStyle) {
767677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        super(context, attrs, defStyle);
777677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        initFromAttributes(context, attrs);
787677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
797677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
807677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    private void initFromAttributes(Context context, AttributeSet attrs) {
817677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProportionalLayout);
827677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
837677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        mDirection = Direction.parse(a.getString(R.styleable.ProportionalLayout_direction));
847677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        mRatio = a.getFloat(R.styleable.ProportionalLayout_ratio, 1.0f);
857677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
867677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        a.recycle();
877677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
887677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
897677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    @Override
907677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
917677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        if (getChildCount() != 1) {
927677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            throw new IllegalStateException("ProportionalLayout requires exactly one child");
937677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        }
947677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
957677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        final View child = getChildAt(0);
967677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
977677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        // Do a first pass to get the optimal size
987677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        measureChild(child, widthMeasureSpec, heightMeasureSpec);
997677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        final int childWidth = child.getMeasuredWidth();
1007677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        final int childHeight = child.getMeasuredHeight();
1017677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1027677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        final int width;
1037677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        final int height;
1047677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        if (mDirection == Direction.heightToWidth) {
1057677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            width = Math.round(childHeight * mRatio);
1067677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            height = childHeight;
1077677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        } else {
1087677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            width = childWidth;
1097677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            height = Math.round(childWidth * mRatio);
1107677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        }
1117677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1127677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        // Do a second pass so that all children are informed of the new size
1137677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        measureChild(child,
1147677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng                MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
1157677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
1167677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1177677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        setMeasuredDimension(
1187677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng                resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));
1197677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
1207677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1217677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    @Override
1227677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1237677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        if (getChildCount() != 1) {
1247677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng            throw new IllegalStateException("ProportionalLayout requires exactly one child");
1257677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        }
1267677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1277677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        final View child = getChildAt(0);
1287677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        child.layout(0, 0, right-left, bottom-top);
1297677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
1307677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1317677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public Direction getDirection() {
1327677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        return mDirection;
1337677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
1347677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1357677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public void setDirection(Direction direction) {
1367677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        mDirection = direction;
1377677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
1387677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1397677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public float getRatio() {
1407677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        return mRatio;
1417677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
1427677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng
1437677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    public void setRatio(float ratio) {
1447677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng        mRatio = ratio;
1457677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng    }
1467677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng}
147