2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.camera.ui;
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;
29 import com.android.camera.Util;
30 import com.android.gallery3d.R;
31 import com.android.gallery3d.common.ApiHelper;
33 public class CameraControls extends RotatableLayout {
35 private static final String TAG = "CAM_Controls";
37 private View mBackgroundView;
38 private View mShutter;
39 private View mSwitcher;
41 private View mIndicators;
42 private View mPreview;
43 private Object mDisplayListener = null;
44 private int mLastRotation = 0;
46 public CameraControls(Context context, AttributeSet attrs) {
47 super(context, attrs);
48 initDisplayListener();
51 public CameraControls(Context context) {
53 initDisplayListener();
56 public void initDisplayListener() {
57 if (ApiHelper.HAS_DISPLAY_LISTENER) {
58 mDisplayListener = new DisplayListener() {
61 public void onDisplayAdded(int arg0) {}
64 public void onDisplayChanged(int arg0) {
69 public void onDisplayRemoved(int arg0) {}
74 private void checkLayoutFlip() {
75 int currentRotation = Util.getDisplayRotation((Activity) getContext());
76 if ((currentRotation - mLastRotation + 360) % 360 == 180) {
77 mLastRotation = currentRotation;
79 getParent().requestLayout();
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);
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);
106 public void onWindowVisibilityChanged(int visibility) {
107 if (visibility == View.VISIBLE) {
108 // Make sure when coming back from onPause, the layout is rotated correctly
114 public void onDetachedFromWindow () {
115 super.onDetachedFromWindow();
116 if (ApiHelper.HAS_DISPLAY_LISTENER) {
117 ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE))
118 .unregisterDisplayListener((DisplayListener) mDisplayListener);
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();
129 // As l,t,r,b are positions relative to parents, we need to convert them
130 // to child's coordinates
135 for (int i = 0; i < getChildCount(); i++) {
136 View v = getChildAt(i);
137 v.layout(l, t, r, b);
139 Rect shutter = new Rect();
140 topRight(mPreview, l, t, r, b);
142 // restrict controls to size
146 l = (l + r - size) / 2;
151 t = (t + b - size) / 2;
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);
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;
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;
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;
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;
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;
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;
218 v.layout(result.left, result.top, result.right, result.bottom);
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);
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;
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;
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;
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;
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;
270 v.layout(l, t, r, b);
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;
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;
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;
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;
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;
306 v.layout(l, t, r, b);
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());
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
319 public void adjustControlsToRightPosition() {
320 int orientation = Util.getDisplayRotation((Activity) getContext());
321 if (orientation >= 180) {
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
336 mBackgroundView.setRotationX(180);
339 mBackgroundView.setRotationY(180);
344 mBackgroundView.setBackgroundResource(R.drawable.switcher_bg);