Home | History | Annotate | Download | only in ui
      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 }