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.app.Activity; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.util.AttributeSet; 23 import android.view.Gravity; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.widget.FrameLayout; 27 28 import com.android.camera.Util; 29 30 /* RotatableLayout rotates itself as well as all its children when orientation 31 * changes. Specifically, when going from portrait to landscape, camera 32 * controls move from the bottom of the screen to right side of the screen 33 * (i.e. counter clockwise). Similarly, when the screen changes to portrait, we 34 * need to move the controls from right side to the bottom of the screen, which 35 * is a clockwise rotation. 36 */ 37 38 public class RotatableLayout extends FrameLayout { 39 40 private static final String TAG = "RotatableLayout"; 41 // Initial orientation of the layout (ORIENTATION_PORTRAIT, or ORIENTATION_LANDSCAPE) 42 private int mInitialOrientation; 43 private int mPrevRotation; 44 private RotationListener mListener = null; 45 public interface RotationListener { 46 public void onRotation(int rotation); 47 } 48 public RotatableLayout(Context context, AttributeSet attrs, int defStyle) { 49 super(context, attrs, defStyle); 50 mInitialOrientation = getResources().getConfiguration().orientation; 51 } 52 53 public RotatableLayout(Context context, AttributeSet attrs) { 54 super(context, attrs); 55 mInitialOrientation = getResources().getConfiguration().orientation; 56 } 57 58 public RotatableLayout(Context context) { 59 super(context); 60 mInitialOrientation = getResources().getConfiguration().orientation; 61 } 62 63 @Override 64 public void onAttachedToWindow() { 65 mPrevRotation = Util.getDisplayRotation((Activity) getContext()); 66 // check if there is any rotation before the view is attached to window 67 int currentOrientation = getResources().getConfiguration().orientation; 68 if (mInitialOrientation == currentOrientation) { 69 return; 70 } 71 if (mInitialOrientation == Configuration.ORIENTATION_LANDSCAPE 72 && currentOrientation == Configuration.ORIENTATION_PORTRAIT) { 73 rotateLayout(true); 74 } else if (mInitialOrientation == Configuration.ORIENTATION_PORTRAIT 75 && currentOrientation == Configuration.ORIENTATION_LANDSCAPE) { 76 rotateLayout(false); 77 } 78 } 79 80 @Override 81 public void onConfigurationChanged(Configuration config) { 82 super.onConfigurationChanged(config); 83 int rotation = Util.getDisplayRotation((Activity) getContext()); 84 if ((rotation - mPrevRotation + 360) % 180 == 0) { 85 mPrevRotation = rotation; 86 return; 87 } 88 boolean clockwise = isClockWiseRotation(mPrevRotation, rotation); 89 rotateLayout(clockwise); 90 mPrevRotation = rotation; 91 } 92 93 protected void rotateLayout(boolean clockwise) { 94 // Change the size of the layout 95 ViewGroup.LayoutParams lp = getLayoutParams(); 96 int width = lp.width; 97 int height = lp.height; 98 lp.height = width; 99 lp.width = height; 100 setLayoutParams(lp); 101 102 // rotate all the children 103 rotateChildren(clockwise); 104 } 105 106 protected void rotateChildren(boolean clockwise) { 107 int childCount = getChildCount(); 108 for (int i = 0; i < childCount; i++) { 109 View child = getChildAt(i); 110 rotate(child, clockwise); 111 } 112 if (mListener != null) mListener.onRotation(clockwise ? 90 : 270); 113 } 114 115 protected void flipChildren() { 116 mPrevRotation = Util.getDisplayRotation((Activity) getContext()); 117 int childCount = getChildCount(); 118 for (int i = 0; i < childCount; i++) { 119 View child = getChildAt(i); 120 flip(child); 121 } 122 if (mListener != null) mListener.onRotation(180); 123 } 124 125 public void setRotationListener(RotationListener listener) { 126 mListener = listener; 127 } 128 129 public static boolean isClockWiseRotation(int prevRotation, int currentRotation) { 130 if (prevRotation == (currentRotation + 90) % 360) { 131 return true; 132 } 133 return false; 134 } 135 136 public static void rotate(View view, boolean isClockwise) { 137 if (isClockwise) { 138 rotateClockwise(view); 139 } else { 140 rotateCounterClockwise(view); 141 } 142 } 143 144 private static boolean contains(int value, int mask) { 145 return (value & mask) == mask; 146 } 147 148 public static void rotateClockwise(View view) { 149 if (view == null) return; 150 LayoutParams lp = (LayoutParams) view.getLayoutParams(); 151 int gravity = lp.gravity; 152 int ngravity = 0; 153 // rotate gravity 154 if (contains(gravity, Gravity.LEFT)) { 155 ngravity |= Gravity.TOP; 156 } 157 if (contains(gravity, Gravity.RIGHT)) { 158 ngravity |= Gravity.BOTTOM; 159 } 160 if (contains(gravity, Gravity.TOP)) { 161 ngravity |= Gravity.RIGHT; 162 } 163 if (contains(gravity, Gravity.BOTTOM)) { 164 ngravity |= Gravity.LEFT; 165 } 166 if (contains(gravity, Gravity.CENTER)) { 167 ngravity |= Gravity.CENTER; 168 } 169 if (contains(gravity, Gravity.CENTER_HORIZONTAL)) { 170 ngravity |= Gravity.CENTER_VERTICAL; 171 } 172 if (contains(gravity, Gravity.CENTER_VERTICAL)) { 173 ngravity |= Gravity.CENTER_HORIZONTAL; 174 } 175 lp.gravity = ngravity; 176 int ml = lp.leftMargin; 177 int mr = lp.rightMargin; 178 int mt = lp.topMargin; 179 int mb = lp.bottomMargin; 180 lp.leftMargin = mb; 181 lp.rightMargin = mt; 182 lp.topMargin = ml; 183 lp.bottomMargin = mr; 184 int width = lp.width; 185 int height = lp.height; 186 lp.width = height; 187 lp.height = width; 188 view.setLayoutParams(lp); 189 } 190 191 public static void rotateCounterClockwise(View view) { 192 if (view == null) return; 193 LayoutParams lp = (LayoutParams) view.getLayoutParams(); 194 int gravity = lp.gravity; 195 int ngravity = 0; 196 // change gravity 197 if (contains(gravity, Gravity.RIGHT)) { 198 ngravity |= Gravity.TOP; 199 } 200 if (contains(gravity, Gravity.LEFT)) { 201 ngravity |= Gravity.BOTTOM; 202 } 203 if (contains(gravity, Gravity.TOP)) { 204 ngravity |= Gravity.LEFT; 205 } 206 if (contains(gravity, Gravity.BOTTOM)) { 207 ngravity |= Gravity.RIGHT; 208 } 209 if (contains(gravity, Gravity.CENTER)) { 210 ngravity |= Gravity.CENTER; 211 } 212 if (contains(gravity, Gravity.CENTER_HORIZONTAL)) { 213 ngravity |= Gravity.CENTER_VERTICAL; 214 } 215 if (contains(gravity, Gravity.CENTER_VERTICAL)) { 216 ngravity |= Gravity.CENTER_HORIZONTAL; 217 } 218 lp.gravity = ngravity; 219 int ml = lp.leftMargin; 220 int mr = lp.rightMargin; 221 int mt = lp.topMargin; 222 int mb = lp.bottomMargin; 223 lp.leftMargin = mt; 224 lp.rightMargin = mb; 225 lp.topMargin = mr; 226 lp.bottomMargin = ml; 227 int width = lp.width; 228 int height = lp.height; 229 lp.width = height; 230 lp.height = width; 231 view.setLayoutParams(lp); 232 } 233 234 // Rotate a given view 180 degrees 235 public static void flip(View view) { 236 rotateClockwise(view); 237 rotateClockwise(view); 238 } 239 }