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}