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.graphics.Rect;
     23 import android.hardware.display.DisplayManager;
     24 import android.hardware.display.DisplayManager.DisplayListener;
     25 import android.util.AttributeSet;
     26 import android.view.View;
     27 import android.widget.FrameLayout;
     28 
     29 import com.android.camera.Util;
     30 import com.android.gallery3d.R;
     31 import com.android.gallery3d.common.ApiHelper;
     32 
     33 public class CameraControls extends RotatableLayout {
     34 
     35     private static final String TAG = "CAM_Controls";
     36 
     37     private View mBackgroundView;
     38     private View mShutter;
     39     private View mSwitcher;
     40     private View mMenu;
     41     private View mIndicators;
     42     private View mPreview;
     43     private Object mDisplayListener = null;
     44     private int mLastRotation = 0;
     45 
     46     public CameraControls(Context context, AttributeSet attrs) {
     47         super(context, attrs);
     48         initDisplayListener();
     49     }
     50 
     51     public CameraControls(Context context) {
     52         super(context);
     53         initDisplayListener();
     54     }
     55 
     56     public void initDisplayListener() {
     57         if (ApiHelper.HAS_DISPLAY_LISTENER) {
     58             mDisplayListener = new DisplayListener() {
     59 
     60                 @Override
     61                 public void onDisplayAdded(int arg0) {}
     62 
     63                 @Override
     64                 public void onDisplayChanged(int arg0) {
     65                     checkLayoutFlip();
     66                 }
     67 
     68                 @Override
     69                 public void onDisplayRemoved(int arg0) {}
     70             };
     71         }
     72     }
     73 
     74     private void checkLayoutFlip() {
     75         int currentRotation = Util.getDisplayRotation((Activity) getContext());
     76         if ((currentRotation - mLastRotation + 360) % 360 == 180) {
     77             mLastRotation = currentRotation;
     78             flipChildren();
     79             getParent().requestLayout();
     80         }
     81     }
     82 
     83     @Override
     84     public void onFinishInflate() {
     85         super.onFinishInflate();
     86         mBackgroundView = findViewById(R.id.blocker);
     87         mSwitcher = findViewById(R.id.camera_switcher);
     88         mShutter = findViewById(R.id.shutter_button);
     89         mMenu = findViewById(R.id.menu);
     90         mIndicators = findViewById(R.id.on_screen_indicators);
     91         mPreview = findViewById(R.id.preview_thumb);
     92     }
     93 
     94     @Override
     95     public void onAttachedToWindow() {
     96         super.onAttachedToWindow();
     97         adjustControlsToRightPosition();
     98         mLastRotation = Util.getDisplayRotation((Activity) getContext());
     99         if (ApiHelper.HAS_DISPLAY_LISTENER) {
    100             ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE))
    101             .registerDisplayListener((DisplayListener) mDisplayListener, null);
    102         }
    103     }
    104 
    105     @Override
    106     public void onWindowVisibilityChanged(int visibility) {
    107         if (visibility == View.VISIBLE) {
    108             // Make sure when coming back from onPause, the layout is rotated correctly
    109             checkLayoutFlip();
    110         }
    111     }
    112 
    113     @Override
    114     public void onDetachedFromWindow () {
    115         super.onDetachedFromWindow();
    116         if (ApiHelper.HAS_DISPLAY_LISTENER) {
    117             ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE))
    118             .unregisterDisplayListener((DisplayListener) mDisplayListener);
    119         }
    120     }
    121 
    122     @Override
    123     public void onLayout(boolean changed, int l, int t, int r, int b) {
    124         mLastRotation = Util.getDisplayRotation((Activity) getContext());
    125         int orientation = getResources().getConfiguration().orientation;
    126         int size = getResources().getDimensionPixelSize(R.dimen.camera_controls_size);
    127         int rotation = getUnifiedRotation();
    128         adjustBackground();
    129         // As l,t,r,b are positions relative to parents, we need to convert them
    130         // to child's coordinates
    131         r = r - l;
    132         b = b - t;
    133         l = 0;
    134         t = 0;
    135         for (int i = 0; i < getChildCount(); i++) {
    136             View v = getChildAt(i);
    137             v.layout(l, t, r, b);
    138         }
    139         Rect shutter = new Rect();
    140         topRight(mPreview, l, t, r, b);
    141         if (size > 0) {
    142             // restrict controls to size
    143             switch (rotation) {
    144             case 0:
    145             case 180:
    146                 l = (l + r - size) / 2;
    147                 r = l + size;
    148                 break;
    149             case 90:
    150             case 270:
    151                 t = (t + b - size) / 2;
    152                 b = t + size;
    153                 break;
    154             }
    155         }
    156         center(mShutter, l, t, r, b, orientation, rotation, shutter);
    157         center(mBackgroundView, l, t, r, b, orientation, rotation, new Rect());
    158         toLeft(mSwitcher, shutter, rotation);
    159         toRight(mMenu, shutter, rotation);
    160         toRight(mIndicators, shutter, rotation);
    161         View retake = findViewById(R.id.btn_retake);
    162         if (retake != null) {
    163             center(retake, shutter, rotation);
    164             View cancel = findViewById(R.id.btn_cancel);
    165             toLeft(cancel, shutter, rotation);
    166             View done = findViewById(R.id.btn_done);
    167             toRight(done, shutter, rotation);
    168         }
    169     }
    170 
    171     private int getUnifiedRotation() {
    172         // all the layout code assumes camera device orientation to be portrait
    173         // adjust rotation for landscape
    174         int orientation = getResources().getConfiguration().orientation;
    175         int rotation = Util.getDisplayRotation((Activity) getContext());
    176         int camOrientation = (rotation % 180 == 0) ? Configuration.ORIENTATION_PORTRAIT
    177                 : Configuration.ORIENTATION_LANDSCAPE;
    178         if (camOrientation != orientation) {
    179             return (rotation + 90) % 360;
    180         }
    181         return rotation;
    182     }
    183 
    184     private void center(View v, int l, int t, int r, int b, int orientation, int rotation, Rect result) {
    185         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
    186         int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin;
    187         int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin;
    188         switch (rotation) {
    189         case 0:
    190             // phone portrait; controls bottom
    191             result.left = (r + l) / 2 - tw / 2 + lp.leftMargin;
    192             result.right = (r + l) / 2 + tw / 2 - lp.rightMargin;
    193             result.bottom = b - lp.bottomMargin;
    194             result.top = b - th + lp.topMargin;
    195             break;
    196         case 90:
    197             // phone landscape: controls right
    198             result.right = r - lp.rightMargin;
    199             result.left = r - tw + lp.leftMargin;
    200             result.top = (b + t) / 2 - th / 2 + lp.topMargin;
    201             result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin;
    202             break;
    203         case 180:
    204             // phone upside down: controls top
    205             result.left = (r + l) / 2 - tw / 2 + lp.leftMargin;
    206             result.right = (r + l) / 2 + tw / 2 - lp.rightMargin;
    207             result.top = t + lp.topMargin;
    208             result.bottom = t + th - lp.bottomMargin;
    209             break;
    210         case 270:
    211             // reverse landscape: controls left
    212             result.left = l + lp.leftMargin;
    213             result.right = l + tw - lp.rightMargin;
    214             result.top = (b + t) / 2 - th / 2 + lp.topMargin;
    215             result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin;
    216             break;
    217         }
    218         v.layout(result.left, result.top, result.right, result.bottom);
    219     }
    220 
    221     private void center(View v, Rect other, int rotation) {
    222         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
    223         int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin;
    224         int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin;
    225         int cx = (other.left + other.right) / 2;
    226         int cy = (other.top + other.bottom) / 2;
    227         v.layout(cx - tw / 2 + lp.leftMargin,
    228                 cy - th / 2 + lp.topMargin,
    229                 cx + tw / 2 - lp.rightMargin,
    230                 cy + th / 2 - lp.bottomMargin);
    231     }
    232 
    233     private void toLeft(View v, Rect other, int rotation) {
    234         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
    235         int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin;
    236         int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin;
    237         int cx = (other.left + other.right) / 2;
    238         int cy = (other.top + other.bottom) / 2;
    239         int l = 0, r = 0, t = 0, b = 0;
    240         switch (rotation) {
    241         case 0:
    242             // portrait, to left of anchor at bottom
    243             l = other.left - tw + lp.leftMargin;
    244             r = other.left - lp.rightMargin;
    245             t = cy - th / 2 + lp.topMargin;
    246             b = cy + th / 2 - lp.bottomMargin;
    247             break;
    248         case 90:
    249             // phone landscape: below anchor on right
    250             l = cx - tw / 2 + lp.leftMargin;
    251             r = cx + tw / 2 - lp.rightMargin;
    252             t = other.bottom + lp.topMargin;
    253             b = other.bottom + th - lp.bottomMargin;
    254             break;
    255         case 180:
    256             // phone upside down: right of anchor at top
    257             l = other.right + lp.leftMargin;
    258             r = other.right + tw - lp.rightMargin;
    259             t = cy - th / 2 + lp.topMargin;
    260             b = cy + th / 2 - lp.bottomMargin;
    261             break;
    262         case 270:
    263             // reverse landscape: above anchor on left
    264             l = cx - tw / 2 + lp.leftMargin;
    265             r = cx + tw / 2 - lp.rightMargin;
    266             t = other.top - th + lp.topMargin;
    267             b = other.top - lp.bottomMargin;
    268             break;
    269         }
    270         v.layout(l, t, r, b);
    271     }
    272 
    273     private void toRight(View v, Rect other, int rotation) {
    274         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
    275         int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin;
    276         int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin;
    277         int cx = (other.left + other.right) / 2;
    278         int cy = (other.top + other.bottom) / 2;
    279         int l = 0, r = 0, t = 0, b = 0;
    280         switch (rotation) {
    281         case 0:
    282             l = other.right + lp.leftMargin;
    283             r = other.right + tw - lp.rightMargin;
    284             t = cy - th / 2 + lp.topMargin;
    285             b = cy + th / 2 - lp.bottomMargin;
    286             break;
    287         case 90:
    288             l = cx - tw / 2 + lp.leftMargin;
    289             r = cx + tw / 2 - lp.rightMargin;
    290             t = other.top - th + lp.topMargin;
    291             b = other.top - lp.bottomMargin;
    292             break;
    293         case 180:
    294             l = other.left - tw + lp.leftMargin;
    295             r = other.left - lp.rightMargin;
    296             t = cy - th / 2 + lp.topMargin;
    297             b = cy + th / 2 - lp.bottomMargin;
    298             break;
    299         case 270:
    300             l = cx - tw / 2 + lp.leftMargin;
    301             r = cx + tw / 2 - lp.rightMargin;
    302             t = other.bottom + lp.topMargin;
    303             b = other.bottom + th - lp.bottomMargin;
    304             break;
    305         }
    306         v.layout(l, t, r, b);
    307     }
    308 
    309     private void topRight(View v, int l, int t, int r, int b) {
    310         // layout using the specific margins; the rotation code messes up the others
    311         int mt = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_top);
    312         int mr = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_right);
    313         v.layout(r - v.getMeasuredWidth() - mr, t + mt, r - mr, t + mt + v.getMeasuredHeight());
    314     }
    315 
    316     // In reverse landscape and reverse portrait, camera controls will be laid out
    317     // on the wrong side of the screen. We need to make adjustment to move the controls
    318     // to the USB side
    319     public void adjustControlsToRightPosition() {
    320         int orientation = getUnifiedRotation();
    321         if (orientation >= 180) {
    322             flipChildren();
    323         }
    324     }
    325 
    326     private void adjustBackground() {
    327         int rotation = getUnifiedRotation();
    328         // remove current drawable and reset rotation
    329         mBackgroundView.setBackgroundDrawable(null);
    330         mBackgroundView.setRotationX(0);
    331         mBackgroundView.setRotationY(0);
    332         // if the switcher background is top aligned we need to flip the background
    333         // drawable vertically; if left aligned, flip horizontally
    334         switch (rotation) {
    335             case 180:
    336                 mBackgroundView.setRotationX(180);
    337                 break;
    338             case 270:
    339                 mBackgroundView.setRotationY(180);
    340                 break;
    341             default:
    342                 break;
    343         }
    344         mBackgroundView.setBackgroundResource(R.drawable.switcher_bg);
    345     }
    346 
    347 }
    348