CameraControls.java revision fa1c3a528de2ec357b8f43aa133feae444899668
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 17package com.android.camera.ui; 18 19import android.app.Activity; 20import android.content.Context; 21import android.content.res.Configuration; 22import android.graphics.Rect; 23import android.hardware.display.DisplayManager; 24import android.hardware.display.DisplayManager.DisplayListener; 25import android.util.AttributeSet; 26import android.view.View; 27import android.widget.FrameLayout; 28 29import com.android.camera.Util; 30import com.android.gallery3d.R; 31import com.android.gallery3d.common.ApiHelper; 32 33public 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 super.onLayout(changed, l, t, r, b); 130 // As l,t,r,b are positions relative to parents, we need to convert them 131 // to child's coordinates 132 r = r - l; 133 b = b - t; 134 l = 0; 135 t = 0; 136 Rect shutter = new Rect(); 137 topRight(mPreview, l, t, r, b, orientation, rotation); 138 if (size > 0) { 139 // restrict controls to size 140 switch (rotation) { 141 case 0: 142 case 180: 143 l = (l + r - size) / 2; 144 r = l + size; 145 break; 146 case 90: 147 case 270: 148 t = (t + b - size) / 2; 149 b = t + size; 150 break; 151 } 152 } 153 center(mShutter, l, t, r, b, orientation, rotation, shutter); 154 center(mBackgroundView, l, t, r, b, orientation, rotation, new Rect()); 155 toLeft(mSwitcher, l, t, r, b, orientation, rotation, shutter); 156 toRight(mMenu, l, t, r, b, orientation, rotation, shutter); 157 toRight(mIndicators, l, t, r, b, orientation, rotation, shutter); 158 View retake = findViewById(R.id.btn_retake); 159 if (retake != null) { 160 Rect retakeRect = new Rect(); 161 center(retake, l, t, r, b, orientation, rotation, retakeRect); 162 View cancel = findViewById(R.id.btn_cancel); 163 toLeft(cancel, l, t, r, b, orientation, rotation, shutter); 164 View done = findViewById(R.id.btn_done); 165 toRight(done, l, t, r, b, orientation, rotation, shutter); 166 } 167 } 168 169 private int getUnifiedRotation() { 170 // all the layout code assumes camera device orientation to be portrait 171 // adjust rotation for landscape 172 int orientation = getResources().getConfiguration().orientation; 173 int rotation = Util.getDisplayRotation((Activity) getContext()); 174 int camOrientation = (rotation % 180 == 0) ? Configuration.ORIENTATION_PORTRAIT 175 : Configuration.ORIENTATION_LANDSCAPE; 176 if (camOrientation != orientation) { 177 return (rotation + 90) % 360; 178 } 179 return rotation; 180 } 181 182 private void center(View v, int l, int t, int r, int b, int orientation, int rotation, Rect result) { 183 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); 184 int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; 185 int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; 186 switch (rotation) { 187 case 0: 188 // phone portrait; controls bottom 189 result.left = (r + l) / 2 - tw / 2 + lp.leftMargin; 190 result.right = (r + l) / 2 + tw / 2 - lp.rightMargin; 191 result.bottom = b - lp.bottomMargin; 192 result.top = b - th + lp.topMargin; 193 break; 194 case 90: 195 // phone landscape: controls right 196 result.right = r - lp.rightMargin; 197 result.left = r - tw + lp.leftMargin; 198 result.top = (b + t) / 2 - th / 2 + lp.topMargin; 199 result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin; 200 break; 201 case 180: 202 // phone upside down: controls top 203 result.left = (r + l) / 2 - tw / 2 + lp.leftMargin; 204 result.right = (r + l) / 2 + tw / 2 - lp.rightMargin; 205 result.top = t + lp.topMargin; 206 result.bottom = t + th - lp.bottomMargin; 207 break; 208 case 270: 209 // reverse landscape: controls left 210 result.left = l + lp.leftMargin; 211 result.right = l + tw - lp.rightMargin; 212 result.top = (b + t) / 2 - th / 2 + lp.topMargin; 213 result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin; 214 break; 215 } 216 v.layout(result.left, result.top, result.right, result.bottom); 217 } 218 219 private void toLeft(View v, int l, int t, int r, int b, int orientation, int rotation, Rect anchor) { 220 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); 221 int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; 222 int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; 223 Rect result = new Rect(); 224 switch (rotation) { 225 case 0: 226 // portrait, to left of anchor at bottom 227 result.right = anchor.left - lp.rightMargin; 228 result.left = anchor.left - tw + lp.leftMargin; 229 result.bottom = b - lp.bottomMargin; 230 result.top = b - th + lp.topMargin; 231 break; 232 case 90: 233 // phone landscape: below anchor on right 234 result.right = r - lp.rightMargin; 235 result.left = r - tw + lp.leftMargin; 236 result.top = anchor.bottom + lp.topMargin; 237 result.bottom = anchor.bottom + th - lp.bottomMargin; 238 break; 239 case 180: 240 // phone upside down: right of anchor at top 241 result.left = anchor.right + lp.leftMargin; 242 result.right = anchor.right + tw - lp.rightMargin; 243 result.top = t + lp.topMargin; 244 result.bottom = t + th - lp.bottomMargin; 245 break; 246 case 270: 247 // reverse landscape: above anchor on left 248 result.left = l + lp.leftMargin; 249 result.right = l + tw - lp.rightMargin; 250 result.bottom = anchor.top - lp.bottomMargin; 251 result.top = anchor.top - th + lp.topMargin; 252 break; 253 } 254 v.layout(result.left, result.top, result.right, result.bottom); 255 } 256 257 private void toRight(View v, int l, int t, int r, int b, int orientation, int rotation, Rect anchor) { 258 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); 259 int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; 260 int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; 261 Rect result = new Rect(); 262 switch (rotation) { 263 case 0: 264 // portrait, right of anchor at bottom 265 result.left = anchor.right + lp.leftMargin; 266 result.right = anchor.right + tw - lp.rightMargin; 267 result.bottom = b - lp.bottomMargin; 268 result.top = b - th + lp.topMargin; 269 break; 270 case 90: 271 // phone landscape: above anchor on right 272 result.right = r - lp.rightMargin; 273 result.left = r - tw + lp.leftMargin; 274 result.bottom = anchor.top - lp.bottomMargin; 275 result.top = anchor.top - th + lp.topMargin; 276 break; 277 case 180: 278 // phone upside down: left of anchor at top 279 result.right = anchor.left - lp.rightMargin; 280 result.left = anchor.left - tw + lp.leftMargin; 281 result.top = t + lp.topMargin; 282 result.bottom = t + th - lp.bottomMargin; 283 break; 284 case 270: 285 // reverse landscape: below anchor on left 286 result.left = l + lp.leftMargin; 287 result.right = l + tw - lp.rightMargin; 288 result.top = anchor.bottom + lp.topMargin; 289 result.bottom = anchor.bottom + th - lp.bottomMargin; 290 break; 291 } 292 v.layout(result.left, result.top, result.right, result.bottom); 293 } 294 295 private void topRight(View v, int l, int t, int r, int b, int orientation, int rotation) { 296 // layout using the specific margins; the rotation code messes up the others 297 int mt = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_top); 298 int mr = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_right); 299 v.layout(r - v.getMeasuredWidth() - mr, t + mt, r - mr, t + mt + v.getMeasuredHeight()); 300 } 301 302 // In reverse landscape and reverse portrait, camera controls will be laid out 303 // on the wrong side of the screen. We need to make adjustment to move the controls 304 // to the USB side 305 public void adjustControlsToRightPosition() { 306 Configuration config = getResources().getConfiguration(); 307 int orientation = Util.getDisplayRotation((Activity) getContext()); 308 if (orientation >= 180) { 309 flipChildren(); 310 } 311 } 312 313 private void adjustBackground() { 314 int rotation = getUnifiedRotation(); 315 // remove current drawable and reset rotation 316 mBackgroundView.setBackgroundDrawable(null); 317 mBackgroundView.setRotationX(0); 318 mBackgroundView.setRotationY(0); 319 // if the switcher background is top aligned we need to flip the background 320 // drawable vertically; if left aligned, flip horizontally 321 switch (rotation) { 322 case 180: 323 mBackgroundView.setRotationX(180); 324 break; 325 case 270: 326 mBackgroundView.setRotationY(180); 327 break; 328 default: 329 break; 330 } 331 mBackgroundView.setBackgroundResource(R.drawable.switcher_bg); 332 } 333 334} 335