1/*
2 * Copyright (C) 2013 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.camera.ui;
18
19import android.content.Context;
20import android.content.res.Configuration;
21import android.util.AttributeSet;
22import android.view.Gravity;
23import android.view.View;
24import android.view.ViewGroup;
25import android.widget.LinearLayout;
26
27import java.util.ArrayList;
28import java.util.List;
29
30/**
31 * TopRightWeightedLayout is a LinearLayout that reorders its
32 * children such that the right most child is the top most child
33 * on an orientation change.
34 */
35public class TopRightWeightedLayout extends LinearLayout {
36    public TopRightWeightedLayout(Context context, AttributeSet attrs) {
37        super(context, attrs);
38    }
39
40    @Override
41    public void onFinishInflate() {
42        Configuration configuration = getContext().getResources().getConfiguration();
43        checkOrientation(configuration.orientation);
44    }
45
46    @Override
47    public void onConfigurationChanged(Configuration configuration) {
48        super.onConfigurationChanged(configuration);
49        checkOrientation(configuration.orientation);
50    }
51
52    /**
53     * Set the orientation of this layout if it has changed,
54     * and center the elements based on the new orientation.
55     */
56    private void checkOrientation(int orientation) {
57        final boolean isHorizontal = LinearLayout.HORIZONTAL == getOrientation();
58        final boolean isPortrait = Configuration.ORIENTATION_PORTRAIT == orientation;
59        if (isPortrait && !isHorizontal) {
60            // Portrait orientation is out of sync, setting to horizontal
61            // and reversing children
62            fixGravityAndPadding(LinearLayout.HORIZONTAL);
63            setOrientation(LinearLayout.HORIZONTAL);
64            reverseChildren();
65            requestLayout();
66        } else if (!isPortrait && isHorizontal) {
67            // Landscape orientation is out of sync, setting to vertical
68            // and reversing children
69            fixGravityAndPadding(LinearLayout.VERTICAL);
70            setOrientation(LinearLayout.VERTICAL);
71            reverseChildren();
72            requestLayout();
73        }
74    }
75
76    /**
77     * Reverse the ordering of the children in this layout.
78     * Note: bringChildToFront produced a non-deterministic ordering.
79     */
80    private void reverseChildren() {
81        List<View> children = new ArrayList<View>();
82        for (int i = getChildCount() - 1; i >= 0; i--) {
83            children.add(getChildAt(i));
84        }
85        for (View v : children) {
86            bringChildToFront(v);
87        }
88    }
89
90    /**
91     * Swap gravity:
92     * left for bottom
93     * right for top
94     * center horizontal for center vertical
95     * etc
96     *
97     * also swap left|right padding for bottom|top
98     */
99    private void fixGravityAndPadding(int direction) {
100        for (int i = 0; i < getChildCount(); i++) {
101            // gravity swap
102            View v = getChildAt(i);
103            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) v.getLayoutParams();
104            int gravity = layoutParams.gravity;
105
106            if (direction == LinearLayout.VERTICAL) {
107                if ((gravity & Gravity.LEFT) != 0) {   // if gravity left is set . . .
108                    gravity &= ~Gravity.LEFT;          // unset left
109                    gravity |= Gravity.BOTTOM;         // and set bottom
110                }
111            } else {
112                if ((gravity & Gravity.BOTTOM) != 0) { // etc
113                    gravity &= ~Gravity.BOTTOM;
114                    gravity |= Gravity.LEFT;
115                }
116            }
117
118            if (direction == LinearLayout.VERTICAL) {
119                if ((gravity & Gravity.RIGHT) != 0) {
120                    gravity &= ~Gravity.RIGHT;
121                    gravity |= Gravity.TOP;
122                }
123            } else {
124                if ((gravity & Gravity.TOP) != 0) {
125                    gravity &= ~Gravity.TOP;
126                    gravity |= Gravity.RIGHT;
127                }
128            }
129
130            // don't mess with children that are centered in both directions
131            if ((gravity & Gravity.CENTER) != Gravity.CENTER) {
132                if (direction == LinearLayout.VERTICAL) {
133                    if ((gravity & Gravity.CENTER_VERTICAL) != 0) {
134                        gravity &= ~ Gravity.CENTER_VERTICAL;
135                        gravity |= Gravity.CENTER_HORIZONTAL;
136                    }
137                } else {
138                    if ((gravity & Gravity.CENTER_HORIZONTAL) != 0) {
139                        gravity &= ~ Gravity.CENTER_HORIZONTAL;
140                        gravity |= Gravity.CENTER_VERTICAL;
141                    }
142                }
143            }
144
145            layoutParams.gravity = gravity;
146
147            // padding swap
148            int paddingLeft = v.getPaddingLeft();
149            int paddingTop = v.getPaddingTop();
150            int paddingRight = v.getPaddingRight();
151            int paddingBottom = v.getPaddingBottom();
152            v.setPadding(paddingBottom, paddingRight, paddingTop, paddingLeft);
153        }
154    }
155}