diff options
Diffstat (limited to 'src/com/android/camera/ui/RotatableLayout.java')
-rw-r--r-- | src/com/android/camera/ui/RotatableLayout.java | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/com/android/camera/ui/RotatableLayout.java b/src/com/android/camera/ui/RotatableLayout.java new file mode 100644 index 000000000..965d62a90 --- /dev/null +++ b/src/com/android/camera/ui/RotatableLayout.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera.ui; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.android.camera.Util; + +/* RotatableLayout rotates itself as well as all its children when orientation + * changes. Specifically, when going from portrait to landscape, camera + * controls move from the bottom of the screen to right side of the screen + * (i.e. counter clockwise). Similarly, when the screen changes to portrait, we + * need to move the controls from right side to the bottom of the screen, which + * is a clockwise rotation. + */ + +public class RotatableLayout extends FrameLayout { + + private static final String TAG = "RotatableLayout"; + // Initial orientation of the layout (ORIENTATION_PORTRAIT, or ORIENTATION_LANDSCAPE) + private int mInitialOrientation; + private int mPrevRotation; + private RotationListener mListener = null; + public interface RotationListener { + public void onRotation(int rotation); + } + public RotatableLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mInitialOrientation = getResources().getConfiguration().orientation; + } + + public RotatableLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mInitialOrientation = getResources().getConfiguration().orientation; + } + + public RotatableLayout(Context context) { + super(context); + mInitialOrientation = getResources().getConfiguration().orientation; + } + + @Override + public void onAttachedToWindow() { + mPrevRotation = Util.getDisplayRotation((Activity) getContext()); + // check if there is any rotation before the view is attached to window + int currentOrientation = getResources().getConfiguration().orientation; + int orientation = getUnifiedRotation(); + if (mInitialOrientation == currentOrientation && orientation < 180) { + return; + } + + if (mInitialOrientation == Configuration.ORIENTATION_LANDSCAPE + && currentOrientation == Configuration.ORIENTATION_PORTRAIT) { + rotateLayout(true); + } else if (mInitialOrientation == Configuration.ORIENTATION_PORTRAIT + && currentOrientation == Configuration.ORIENTATION_LANDSCAPE) { + rotateLayout(false); + } + // In reverse landscape and reverse portrait, camera controls will be laid out + // on the wrong side of the screen. We need to make adjustment to move the controls + // to the USB side + if (orientation >= 180) { + flipChildren(); + } + } + + protected int getUnifiedRotation() { + // all the layout code assumes camera device orientation to be portrait + // adjust rotation for landscape + int orientation = getResources().getConfiguration().orientation; + int rotation = Util.getDisplayRotation((Activity) getContext()); + int camOrientation = (rotation % 180 == 0) ? Configuration.ORIENTATION_PORTRAIT + : Configuration.ORIENTATION_LANDSCAPE; + if (camOrientation != orientation) { + return (rotation + 90) % 360; + } + return rotation; + } + + public void checkLayoutFlip() { + int currentRotation = Util.getDisplayRotation((Activity) getContext()); + if ((currentRotation - mPrevRotation + 360) % 360 == 180) { + mPrevRotation = currentRotation; + flipChildren(); + getParent().requestLayout(); + } + } + + @Override + public void onWindowVisibilityChanged(int visibility) { + if (visibility == View.VISIBLE) { + // Make sure when coming back from onPause, the layout is rotated correctly + checkLayoutFlip(); + } + } + + @Override + public void onConfigurationChanged(Configuration config) { + super.onConfigurationChanged(config); + int rotation = Util.getDisplayRotation((Activity) getContext()); + int diff = (rotation - mPrevRotation + 360) % 360; + if ( diff == 0) { + // No rotation + return; + } else if (diff == 180) { + // 180-degree rotation + mPrevRotation = rotation; + flipChildren(); + return; + } + // 90 or 270-degree rotation + boolean clockwise = isClockWiseRotation(mPrevRotation, rotation); + mPrevRotation = rotation; + rotateLayout(clockwise); + } + + protected void rotateLayout(boolean clockwise) { + // Change the size of the layout + ViewGroup.LayoutParams lp = getLayoutParams(); + int width = lp.width; + int height = lp.height; + lp.height = width; + lp.width = height; + setLayoutParams(lp); + + // rotate all the children + rotateChildren(clockwise); + } + + protected void rotateChildren(boolean clockwise) { + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + rotate(child, clockwise); + } + if (mListener != null) mListener.onRotation(clockwise ? 90 : 270); + } + + protected void flipChildren() { + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + flip(child); + } + if (mListener != null) mListener.onRotation(180); + } + + public void setRotationListener(RotationListener listener) { + mListener = listener; + } + + public static boolean isClockWiseRotation(int prevRotation, int currentRotation) { + if (prevRotation == (currentRotation + 90) % 360) { + return true; + } + return false; + } + + public static void rotate(View view, boolean isClockwise) { + if (isClockwise) { + rotateClockwise(view); + } else { + rotateCounterClockwise(view); + } + } + + private static boolean contains(int value, int mask) { + return (value & mask) == mask; + } + + public static void rotateClockwise(View view) { + if (view == null) return; + LayoutParams lp = (LayoutParams) view.getLayoutParams(); + int gravity = lp.gravity; + int ngravity = 0; + // rotate gravity + if (contains(gravity, Gravity.LEFT)) { + ngravity |= Gravity.TOP; + } + if (contains(gravity, Gravity.RIGHT)) { + ngravity |= Gravity.BOTTOM; + } + if (contains(gravity, Gravity.TOP)) { + ngravity |= Gravity.RIGHT; + } + if (contains(gravity, Gravity.BOTTOM)) { + ngravity |= Gravity.LEFT; + } + if (contains(gravity, Gravity.CENTER)) { + ngravity |= Gravity.CENTER; + } + if (contains(gravity, Gravity.CENTER_HORIZONTAL)) { + ngravity |= Gravity.CENTER_VERTICAL; + } + if (contains(gravity, Gravity.CENTER_VERTICAL)) { + ngravity |= Gravity.CENTER_HORIZONTAL; + } + lp.gravity = ngravity; + int ml = lp.leftMargin; + int mr = lp.rightMargin; + int mt = lp.topMargin; + int mb = lp.bottomMargin; + lp.leftMargin = mb; + lp.rightMargin = mt; + lp.topMargin = ml; + lp.bottomMargin = mr; + int width = lp.width; + int height = lp.height; + lp.width = height; + lp.height = width; + view.setLayoutParams(lp); + } + + public static void rotateCounterClockwise(View view) { + if (view == null) return; + LayoutParams lp = (LayoutParams) view.getLayoutParams(); + int gravity = lp.gravity; + int ngravity = 0; + // change gravity + if (contains(gravity, Gravity.RIGHT)) { + ngravity |= Gravity.TOP; + } + if (contains(gravity, Gravity.LEFT)) { + ngravity |= Gravity.BOTTOM; + } + if (contains(gravity, Gravity.TOP)) { + ngravity |= Gravity.LEFT; + } + if (contains(gravity, Gravity.BOTTOM)) { + ngravity |= Gravity.RIGHT; + } + if (contains(gravity, Gravity.CENTER)) { + ngravity |= Gravity.CENTER; + } + if (contains(gravity, Gravity.CENTER_HORIZONTAL)) { + ngravity |= Gravity.CENTER_VERTICAL; + } + if (contains(gravity, Gravity.CENTER_VERTICAL)) { + ngravity |= Gravity.CENTER_HORIZONTAL; + } + lp.gravity = ngravity; + int ml = lp.leftMargin; + int mr = lp.rightMargin; + int mt = lp.topMargin; + int mb = lp.bottomMargin; + lp.leftMargin = mt; + lp.rightMargin = mb; + lp.topMargin = mr; + lp.bottomMargin = ml; + int width = lp.width; + int height = lp.height; + lp.width = height; + lp.height = width; + view.setLayoutParams(lp); + } + + // Rotate a given view 180 degrees + public static void flip(View view) { + rotateClockwise(view); + rotateClockwise(view); + } +}
\ No newline at end of file |