Anchor camera controls when flipping device

Also adjusted margins for camera root view to avoid covering undo bar

Bug: 8758513
Bug: 8714114
Change-Id: If27f55a40f95402923d59d162db0c7cc29eabba4
diff --git a/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java b/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java
index f6439f1..dde4c56 100644
--- a/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java
+++ b/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java
@@ -195,6 +195,9 @@
     public static final boolean HAS_MEDIA_MUXER =
                     Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2;
 
+    public static final boolean HAS_DISPLAY_LISTENER =
+            Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1;
+
     public static int getIntFieldIfExists(Class<?> klass, String fieldName,
             Class<?> obj, int defaultVal) {
         try {
diff --git a/src/com/android/camera/ui/CameraControls.java b/src/com/android/camera/ui/CameraControls.java
index f7af52c..5d2f123 100644
--- a/src/com/android/camera/ui/CameraControls.java
+++ b/src/com/android/camera/ui/CameraControls.java
@@ -20,13 +20,15 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
 import android.util.AttributeSet;
-import android.view.Gravity;
 import android.view.View;
 import android.widget.FrameLayout;
 
 import com.android.camera.Util;
 import com.android.gallery3d.R;
+import com.android.gallery3d.common.ApiHelper;
 
 public class CameraControls extends RotatableLayout {
 
@@ -38,19 +40,40 @@
     private View mMenu;
     private View mIndicators;
     private View mPreview;
+    private Object mDisplayListener = null;
+    private int mLastRotation = 0;
 
     public CameraControls(Context context, AttributeSet attrs) {
         super(context, attrs);
+        initDisplayListener();
     }
 
     public CameraControls(Context context) {
         super(context);
+        initDisplayListener();
     }
 
-    @Override
-    public void onConfigurationChanged(Configuration config) {
-        super.onConfigurationChanged(config);
-        adjustBackground();
+    public void initDisplayListener() {
+        if (ApiHelper.HAS_DISPLAY_LISTENER) {
+            mDisplayListener = new DisplayListener() {
+
+                @Override
+                public void onDisplayAdded(int arg0) {}
+
+                @Override
+                public void onDisplayChanged(int arg0) {
+                    int currentRotation = Util.getDisplayRotation((Activity) getContext());
+                    if ((currentRotation - mLastRotation) % 180 == 0) {
+                        flipChildren();
+                        getParent().requestLayout();
+                    }
+                    mLastRotation = currentRotation;
+                }
+
+                @Override
+                public void onDisplayRemoved(int arg0) {}
+            };
+        }
     }
 
     @Override
@@ -65,12 +88,38 @@
     }
 
     @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        adjustControlsToRightPosition();
+        mLastRotation = Util.getDisplayRotation((Activity) getContext());
+        if (ApiHelper.HAS_DISPLAY_LISTENER) {
+            ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE))
+            .registerDisplayListener((DisplayListener) mDisplayListener, null);
+        }
+    }
+
+    @Override
+    public void onDetachedFromWindow () {
+        super.onDetachedFromWindow();
+        if (ApiHelper.HAS_DISPLAY_LISTENER) {
+            ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE))
+            .unregisterDisplayListener((DisplayListener) mDisplayListener);
+        }
+    }
+
+    @Override
     public void onLayout(boolean changed, int l, int t, int r, int b) {
         int orientation = getResources().getConfiguration().orientation;
-        int rotation = Util.getDisplayRotation((Activity) getContext());
         int size = getResources().getDimensionPixelSize(R.dimen.camera_controls_size);
-        rotation = correctRotation(rotation, orientation);
+        int rotation = getUnifiedRotation();
+        adjustBackground();
         super.onLayout(changed, l, t, r, b);
+        // As l,t,r,b are positions relative to parents, we need to convert them
+        // to child's coordinates
+        r = r - l;
+        b = b - t;
+        l = 0;
+        t = 0;
         Rect shutter = new Rect();
         topRight(mPreview, l, t, r, b, orientation, rotation);
         if (size > 0) {
@@ -104,9 +153,11 @@
         }
     }
 
-    private int correctRotation(int rotation, int orientation) {
+    private 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) {
@@ -241,27 +292,28 @@
     public void adjustControlsToRightPosition() {
         Configuration config = getResources().getConfiguration();
         int orientation = Util.getDisplayRotation((Activity) getContext());
-        if (orientation == 270 && config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+        if (orientation >= 180) {
             flipChildren();
         }
-        if (orientation == 180 && config.orientation == Configuration.ORIENTATION_PORTRAIT) {
-            flipChildren();
-        }
-        adjustBackground();
     }
 
     private void adjustBackground() {
+        int rotation = getUnifiedRotation();
         // remove current drawable and reset rotation
         mBackgroundView.setBackgroundDrawable(null);
         mBackgroundView.setRotationX(0);
         mBackgroundView.setRotationY(0);
         // if the switcher background is top aligned we need to flip the background
         // drawable vertically; if left aligned, flip horizontally
-        int gravity = ((LayoutParams) mBackgroundView.getLayoutParams()).gravity;
-        if ((gravity & Gravity.TOP) == Gravity.TOP) {
-            mBackgroundView.setRotationX(180);
-        } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
-            mBackgroundView.setRotationY(180);
+        switch (rotation) {
+            case 180:
+                mBackgroundView.setRotationX(180);
+                break;
+            case 270:
+                mBackgroundView.setRotationY(180);
+                break;
+            default:
+                break;
         }
         mBackgroundView.setBackgroundResource(R.drawable.switcher_bg);
     }
diff --git a/src/com/android/camera/ui/CameraRootView.java b/src/com/android/camera/ui/CameraRootView.java
index 9e3469f..0cff144 100644
--- a/src/com/android/camera/ui/CameraRootView.java
+++ b/src/com/android/camera/ui/CameraRootView.java
@@ -29,14 +29,14 @@
 import com.android.camera.Util;
 import com.android.gallery3d.R;
 
-public class CameraRootView extends RelativeLayout
-    implements RotatableLayout.RotationListener {
+public class CameraRootView extends RelativeLayout {
 
     private int mTopMargin = 0;
     private int mBottomMargin = 0;
     private int mLeftMargin = 0;
     private int mRightMargin = 0;
     private int mOffset = 0;
+    private Rect mCurrentInsets;
     public CameraRootView(Context context, AttributeSet attrs) {
         super(context, attrs);
         // Layout the window as if we did not need navigation bar
@@ -47,64 +47,68 @@
     @Override
     protected boolean fitSystemWindows(Rect insets) {
         super.fitSystemWindows(insets);
+        mCurrentInsets = insets;
         // insets include status bar, navigation bar, etc
         // In this case, we are only concerned with the size of nav bar
-        if (mOffset > 0) {
-            // Add margin if necessary to the view to ensure nothing is covered
-            // by navigation bar
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-            int right, bottom;
-            if (insets.right > 0) {
-                // navigation bar on the right
-                right = mRightMargin > 0 ? 0 : insets.right;
-                bottom = 0;
-            } else {
-                // navigation bar on the bottom
-                bottom = mBottomMargin > 0 ? 0 : insets.bottom;
-                right = 0;
-            }
-            lp.setMargins(mLeftMargin, mTopMargin, mRightMargin + right, mBottomMargin + bottom);
-            return true;
-        }
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        if (mOffset > 0) return true;
+
         if (insets.bottom > 0) {
             mOffset = insets.bottom;
         } else if (insets.right > 0) {
             mOffset = insets.right;
         }
-        Configuration config = getResources().getConfiguration();
-        if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
-            mBottomMargin = mOffset;
-        } else if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            mRightMargin = mOffset;
-        }
-        lp.setMargins( mLeftMargin, mTopMargin, mRightMargin, mBottomMargin);
-        CameraControls controls = (CameraControls) findViewById(R.id.camera_controls);
-        if (controls != null) {
-            controls.setRotationListener(this);
-            controls.adjustControlsToRightPosition();
-        }
         return true;
     }
 
-    @Override
-    public void onRotation(int rotation) {
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-        int b = mBottomMargin;
-        int t = mTopMargin;
-        int l = mLeftMargin;
-        int r = mRightMargin;
-        rotation = (rotation + 360) % 360;
-        if (rotation == 90) {
-            lp.setMargins(b, l, t, r);
-        } else if (rotation == 270) {
-            lp.setMargins(t, r, b, l);
-        } else if (rotation == 180) {
-            lp.setMargins(r, b, l, t);
+    public void onLayout(boolean changed, int l, int t, int r, int b) {
+        int rotation = Util.getDisplayRotation((Activity) getContext());
+        // all the layout code assumes camera device orientation to be portrait
+        // adjust rotation for landscape
+        int orientation = getResources().getConfiguration().orientation;
+        int camOrientation = (rotation % 180 == 0) ? Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        if (camOrientation != orientation) {
+            rotation = (rotation + 90) % 360;
         }
-        mLeftMargin = lp.leftMargin;
-        mTopMargin = lp.topMargin;
-        mRightMargin = lp.rightMargin;
-        mBottomMargin = lp.bottomMargin;
+        // calculate margins
+        int left = 0;
+        int right = 0;
+        int bottom = 0;
+        int top = 0;
+        switch (rotation) {
+            case 0:
+                bottom += mOffset;
+                break;
+            case 90:
+                right += mOffset;
+                break;
+            case 180:
+                top += mOffset;
+                break;
+            case 270:
+                left += mOffset;
+                break;
+        }
+        if (mCurrentInsets.right > 0) {
+            // navigation bar on the right
+            right = right > 0 ? right : mCurrentInsets.right;
+        } else {
+            // navigation bar on the bottom
+            bottom = bottom > 0 ? bottom : mCurrentInsets.bottom;
+        }
+        for (int i = 0; i < getChildCount(); i++) {
+            View v = getChildAt(i);
+            if (v instanceof CameraControls) {
+                // Lay out camera controls to fill the short side of the screen
+                // so that they stay in place during rotation
+                if (rotation % 180 == 0) {
+                    v.layout(l, t + top, r, b - bottom);
+                } else {
+                    v.layout(l + left, t, r - right, b);
+                }
+            } else {
+                v.layout(l + left, t + top, r - right, b - bottom);
+            }
+        }
     }
 }