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 
17 package com.android.camera.ui;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.util.AttributeSet;
22 import android.view.Gravity;
23 import android.view.View;
24 import android.view.ViewGroup;
25 import android.widget.LinearLayout;
26 
27 import java.util.ArrayList;
28 import 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  */
35 public class TopRightWeightedLayout extends LinearLayout {
TopRightWeightedLayout(Context context, AttributeSet attrs)36     public TopRightWeightedLayout(Context context, AttributeSet attrs) {
37         super(context, attrs);
38     }
39 
40     @Override
onFinishInflate()41     public void onFinishInflate() {
42         Configuration configuration = getContext().getResources().getConfiguration();
43         checkOrientation(configuration.orientation);
44     }
45 
46     @Override
onConfigurationChanged(Configuration configuration)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      */
checkOrientation(int orientation)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      */
reverseChildren()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      */
fixGravityAndPadding(int direction)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 }