| /* |
| * 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.graphics.Rect; |
| 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; |
| |
| public class CameraControls extends RotatableLayout { |
| |
| private static final String TAG = "CAM_Controls"; |
| |
| private View mBackgroundView; |
| private View mShutter; |
| private View mSwitcher; |
| private View mMenu; |
| private View mIndicators; |
| private View mPreview; |
| |
| public CameraControls(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| } |
| |
| public CameraControls(Context context) { |
| super(context); |
| } |
| |
| @Override |
| public void onConfigurationChanged(Configuration config) { |
| super.onConfigurationChanged(config); |
| adjustBackground(); |
| } |
| |
| @Override |
| public void onFinishInflate() { |
| super.onFinishInflate(); |
| mBackgroundView = findViewById(R.id.blocker); |
| mSwitcher = findViewById(R.id.camera_switcher); |
| mShutter = findViewById(R.id.shutter_button); |
| mMenu = findViewById(R.id.menu); |
| mIndicators = findViewById(R.id.on_screen_indicators); |
| mPreview = findViewById(R.id.preview_thumb); |
| } |
| |
| @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); |
| super.onLayout(changed, l, t, r, b); |
| Rect shutter = new Rect(); |
| topRight(mPreview, l, t, r, b, orientation, rotation); |
| if (size > 0) { |
| // restrict controls to size |
| switch (rotation) { |
| case 0: |
| case 180: |
| l = (l + r - size) / 2; |
| r = l + size; |
| break; |
| case 90: |
| case 270: |
| t = (t + b - size) / 2; |
| b = t + size; |
| break; |
| } |
| } |
| center(mShutter, l, t, r, b, orientation, rotation, shutter); |
| center(mBackgroundView, l, t, r, b, orientation, rotation, new Rect()); |
| toLeft(mSwitcher, l, t, r, b, orientation, rotation, shutter); |
| toRight(mMenu, l, t, r, b, orientation, rotation, shutter); |
| toRight(mIndicators, l, t, r, b, orientation, rotation, shutter); |
| View retake = findViewById(R.id.btn_retake); |
| if (retake != null) { |
| Rect retakeRect = new Rect(); |
| center(retake, l, t, r, b, orientation, rotation, retakeRect); |
| View cancel = findViewById(R.id.btn_cancel); |
| toLeft(cancel, l, t, r, b, orientation, rotation, shutter); |
| View done = findViewById(R.id.btn_done); |
| toRight(done, l, t, r, b, orientation, rotation, shutter); |
| } |
| } |
| |
| private int correctRotation(int rotation, int orientation) { |
| // all the layout code assumes camera device orientation to be portrait |
| // adjust rotation for landscape |
| int camOrientation = (rotation % 180 == 0) ? Configuration.ORIENTATION_PORTRAIT |
| : Configuration.ORIENTATION_LANDSCAPE; |
| if (camOrientation != orientation) { |
| return (rotation + 90) % 360; |
| } |
| return rotation; |
| } |
| |
| private void center(View v, int l, int t, int r, int b, int orientation, int rotation, Rect result) { |
| FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); |
| int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; |
| int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; |
| switch (rotation) { |
| case 0: |
| // phone portrait; controls bottom |
| result.left = (r + l) / 2 - tw / 2 + lp.leftMargin; |
| result.right = (r + l) / 2 + tw / 2 - lp.rightMargin; |
| result.bottom = b - lp.bottomMargin; |
| result.top = b - th + lp.topMargin; |
| break; |
| case 90: |
| // phone landscape: controls right |
| result.right = r - lp.rightMargin; |
| result.left = r - tw + lp.leftMargin; |
| result.top = (b + t) / 2 - th / 2 + lp.topMargin; |
| result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin; |
| break; |
| case 180: |
| // phone upside down: controls top |
| result.left = (r + l) / 2 - tw / 2 + lp.leftMargin; |
| result.right = (r + l) / 2 + tw / 2 - lp.rightMargin; |
| result.top = t + lp.topMargin; |
| result.bottom = t + th - lp.bottomMargin; |
| break; |
| case 270: |
| // reverse landscape: controls left |
| result.left = l + lp.leftMargin; |
| result.right = l + tw - lp.rightMargin; |
| result.top = (b + t) / 2 - th / 2 + lp.topMargin; |
| result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin; |
| break; |
| } |
| v.layout(result.left, result.top, result.right, result.bottom); |
| } |
| |
| private void toLeft(View v, int l, int t, int r, int b, int orientation, int rotation, Rect anchor) { |
| FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); |
| int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; |
| int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; |
| Rect result = new Rect(); |
| switch (rotation) { |
| case 0: |
| // portrait, to left of anchor at bottom |
| result.right = anchor.left - lp.rightMargin; |
| result.left = anchor.left - tw + lp.leftMargin; |
| result.bottom = b - lp.bottomMargin; |
| result.top = b - th + lp.topMargin; |
| break; |
| case 90: |
| // phone landscape: below anchor on right |
| result.right = r - lp.rightMargin; |
| result.left = r - tw + lp.leftMargin; |
| result.top = anchor.bottom + lp.topMargin; |
| result.bottom = anchor.bottom + th - lp.bottomMargin; |
| break; |
| case 180: |
| // phone upside down: right of anchor at top |
| result.left = anchor.right + lp.leftMargin; |
| result.right = anchor.right + tw - lp.rightMargin; |
| result.top = t + lp.topMargin; |
| result.bottom = t + th - lp.bottomMargin; |
| break; |
| case 270: |
| // reverse landscape: above anchor on left |
| result.left = l + lp.leftMargin; |
| result.right = l + tw - lp.rightMargin; |
| result.bottom = anchor.top - lp.bottomMargin; |
| result.top = anchor.top - th + lp.topMargin; |
| break; |
| } |
| v.layout(result.left, result.top, result.right, result.bottom); |
| } |
| |
| private void toRight(View v, int l, int t, int r, int b, int orientation, int rotation, Rect anchor) { |
| FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); |
| int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; |
| int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; |
| Rect result = new Rect(); |
| switch (rotation) { |
| case 0: |
| // portrait, right of anchor at bottom |
| result.left = anchor.right + lp.leftMargin; |
| result.right = anchor.right + tw - lp.rightMargin; |
| result.bottom = b - lp.bottomMargin; |
| result.top = b - th + lp.topMargin; |
| break; |
| case 90: |
| // phone landscape: above anchor on right |
| result.right = r - lp.rightMargin; |
| result.left = r - tw + lp.leftMargin; |
| result.bottom = anchor.top - lp.bottomMargin; |
| result.top = anchor.top - th + lp.topMargin; |
| break; |
| case 180: |
| // phone upside down: left of anchor at top |
| result.right = anchor.left - lp.rightMargin; |
| result.left = anchor.left - tw + lp.leftMargin; |
| result.top = t + lp.topMargin; |
| result.bottom = t + th - lp.bottomMargin; |
| break; |
| case 270: |
| // reverse landscape: below anchor on left |
| result.left = l + lp.leftMargin; |
| result.right = l + tw - lp.rightMargin; |
| result.top = anchor.bottom + lp.topMargin; |
| result.bottom = anchor.bottom + th - lp.bottomMargin; |
| break; |
| } |
| v.layout(result.left, result.top, result.right, result.bottom); |
| } |
| |
| private void topRight(View v, int l, int t, int r, int b, int orientation, int rotation) { |
| // layout using the specific margins; the rotation code messes up the others |
| int mt = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_top); |
| int mr = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_right); |
| v.layout(r - v.getMeasuredWidth() - mr, t + mt, r - mr, t + mt + v.getMeasuredHeight()); |
| } |
| |
| // 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 |
| public void adjustControlsToRightPosition() { |
| Configuration config = getResources().getConfiguration(); |
| int orientation = Util.getDisplayRotation((Activity) getContext()); |
| if (orientation == 270 && config.orientation == Configuration.ORIENTATION_LANDSCAPE) { |
| flipChildren(); |
| } |
| if (orientation == 180 && config.orientation == Configuration.ORIENTATION_PORTRAIT) { |
| flipChildren(); |
| } |
| adjustBackground(); |
| } |
| |
| private void adjustBackground() { |
| // 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); |
| } |
| mBackgroundView.setBackgroundResource(R.drawable.switcher_bg); |
| } |
| |
| } |