RotatableLayout.java revision 8d2d0f5f0f7fffce9dbcc70da6924af545eba26d
1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen/*
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * Copyright (C) 2013 The Android Open Source Project
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * Licensed under the Apache License, Version 2.0 (the "License");
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * you may not use this file except in compliance with the License.
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * You may obtain a copy of the License at
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *      http://www.apache.org/licenses/LICENSE-2.0
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * Unless required by applicable law or agreed to in writing, software
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * distributed under the License is distributed on an "AS IS" BASIS,
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * See the License for the specific language governing permissions and
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * limitations under the License.
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenpackage com.android.camera.ui;
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.app.Activity;
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.content.Context;
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.content.res.Configuration;
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.util.AttributeSet;
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.view.Gravity;
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.view.View;
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.view.ViewGroup;
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport android.widget.FrameLayout;
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport com.android.camera.Util;
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen/* RotatableLayout rotates itself as well as all its children when orientation
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * changes. Specifically, when going from portrait to landscape, camera
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * controls move from the bottom of the screen to right side of the screen
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * (i.e. counter clockwise). Similarly, when the screen changes to portrait, we
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * need to move the controls from right side to the bottom of the screen, which
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * is a clockwise rotation.
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenpublic class RotatableLayout extends FrameLayout {
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    private static final String TAG = "RotatableLayout";
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    private int mPrevRotation;
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    public RotatableLayout(Context context, AttributeSet attrs, int defStyle) {
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        super(context, attrs, defStyle);
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    public RotatableLayout(Context context, AttributeSet attrs) {
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        super(context, attrs);
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    public RotatableLayout(Context context) {
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        super(context);
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    @Override
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    public void onFinishInflate() { // get initial orientation
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        mPrevRotation = Util.getDisplayRotation((Activity) getContext());
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    @Override
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    public void onConfigurationChanged(Configuration config) {
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        super.onConfigurationChanged(config);
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // Change the size of the layout
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ViewGroup.LayoutParams lp = getLayoutParams();
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        int width = lp.width;
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        int height = lp.height;
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        lp.height = width;
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        lp.width = height;
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        setLayoutParams(lp);
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // rotate all the children
70        int rotation = Util.getDisplayRotation((Activity) getContext());
71        boolean clockwise = isClockWiseRotation(mPrevRotation, rotation);
72        mPrevRotation = rotation;
73        int childCount = getChildCount();
74        for (int i = 0; i < childCount; i++) {
75            View child = getChildAt(i);
76            rotate(child, clockwise);
77        }
78    }
79
80    public static boolean isClockWiseRotation(int prevRotation, int currentRotation) {
81        if (prevRotation == (currentRotation + 90) % 360) {
82            return true;
83        }
84        return false;
85    }
86
87    public static void rotate(View view, boolean isClockwise) {
88        if (isClockwise) {
89            rotateClockwise(view);
90        } else {
91            rotateCounterClockwise(view);
92        }
93    }
94
95    private static boolean contains(int value, int mask) {
96        return (value & mask) == mask;
97    }
98
99    public static void rotateClockwise(View view) {
100        if (view == null) return;
101        LayoutParams lp = (LayoutParams) view.getLayoutParams();
102        int gravity = lp.gravity;
103        int ngravity = 0;
104        // rotate gravity
105        if (contains(gravity, Gravity.LEFT)) {
106            ngravity |= Gravity.TOP;
107        }
108        if (contains(gravity, Gravity.RIGHT)) {
109            ngravity |= Gravity.BOTTOM;
110        }
111        if (contains(gravity, Gravity.TOP)) {
112            ngravity |= Gravity.RIGHT;
113        }
114        if (contains(gravity, Gravity.BOTTOM)) {
115            ngravity |= Gravity.LEFT;
116        }
117        if (contains(gravity, Gravity.CENTER)) {
118            ngravity |= Gravity.CENTER;
119        }
120        if (contains(gravity, Gravity.CENTER_HORIZONTAL)) {
121            ngravity |= Gravity.CENTER_VERTICAL;
122        }
123        if (contains(gravity, Gravity.CENTER_VERTICAL)) {
124            ngravity |= Gravity.CENTER_HORIZONTAL;
125        }
126        lp.gravity = ngravity;
127        int ml = lp.leftMargin;
128        int mr = lp.rightMargin;
129        int mt = lp.topMargin;
130        int mb = lp.bottomMargin;
131        lp.leftMargin = mb;
132        lp.rightMargin = mt;
133        lp.topMargin = ml;
134        lp.bottomMargin = mr;
135        int width = lp.width;
136        int height = lp.height;
137        lp.width = height;
138        lp.height = width;
139        view.setLayoutParams(lp);
140    }
141
142    public static void rotateCounterClockwise(View view) {
143        if (view == null) return;
144        LayoutParams lp = (LayoutParams) view.getLayoutParams();
145        int gravity = lp.gravity;
146        int ngravity = 0;
147        // change gravity
148        if (contains(gravity, Gravity.RIGHT)) {
149            ngravity |= Gravity.TOP;
150        }
151        if (contains(gravity, Gravity.LEFT)) {
152            ngravity |= Gravity.BOTTOM;
153        }
154        if (contains(gravity, Gravity.TOP)) {
155            ngravity |= Gravity.LEFT;
156        }
157        if (contains(gravity, Gravity.BOTTOM)) {
158            ngravity |= Gravity.RIGHT;
159        }
160        if (contains(gravity, Gravity.CENTER)) {
161            ngravity |= Gravity.CENTER;
162        }
163        if (contains(gravity, Gravity.CENTER_HORIZONTAL)) {
164            ngravity |= Gravity.CENTER_VERTICAL;
165        }
166        if (contains(gravity, Gravity.CENTER_VERTICAL)) {
167            ngravity |= Gravity.CENTER_HORIZONTAL;
168        }
169        lp.gravity = ngravity;
170        int ml = lp.leftMargin;
171        int mr = lp.rightMargin;
172        int mt = lp.topMargin;
173        int mb = lp.bottomMargin;
174        lp.leftMargin = mt;
175        lp.rightMargin = mb;
176        lp.topMargin = mr;
177        lp.bottomMargin = ml;
178        int width = lp.width;
179        int height = lp.height;
180        lp.width = height;
181        lp.height = width;
182        view.setLayoutParams(lp);
183    }
184}