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.content.Context; 20 import android.graphics.Rect; 21 import android.util.AttributeSet; 22 import android.view.View; 23 import android.widget.FrameLayout; 24 25 import com.android.camera2.R; 26 27 public class CameraControls extends RotatableLayout { 28 29 private static final String TAG = "CAM_Controls"; 30 31 private View mBackgroundView; 32 private View mShutter; 33 private View mSwitcher; 34 private View mMenu; 35 private View mIndicators; 36 private View mPreview; 37 38 public CameraControls(Context context, AttributeSet attrs) { 39 super(context, attrs); 40 setMeasureAllChildren(true); 41 } 42 43 public CameraControls(Context context) { 44 super(context); 45 setMeasureAllChildren(true); 46 } 47 48 @Override 49 public void onFinishInflate() { 50 super.onFinishInflate(); 51 mBackgroundView = findViewById(R.id.blocker); 52 mSwitcher = findViewById(R.id.camera_switcher); 53 mShutter = findViewById(R.id.shutter_button); 54 mMenu = findViewById(R.id.menu); 55 mIndicators = findViewById(R.id.on_screen_indicators); 56 mPreview = findViewById(R.id.preview_thumb); 57 } 58 59 @Override 60 public void onLayout(boolean changed, int l, int t, int r, int b) { 61 int orientation = getResources().getConfiguration().orientation; 62 int size = getResources().getDimensionPixelSize(R.dimen.camera_controls_size); 63 int rotation = getUnifiedRotation(); 64 adjustBackground(); 65 // As l,t,r,b are positions relative to parents, we need to convert them 66 // to child's coordinates 67 r = r - l; 68 b = b - t; 69 l = 0; 70 t = 0; 71 for (int i = 0; i < getChildCount(); i++) { 72 View v = getChildAt(i); 73 v.layout(l, t, r, b); 74 } 75 Rect shutter = new Rect(); 76 topRight(mPreview, l, t, r, b); 77 if (size > 0) { 78 // restrict controls to size 79 switch (rotation) { 80 case 0: 81 case 180: 82 l = (l + r - size) / 2; 83 r = l + size; 84 break; 85 case 90: 86 case 270: 87 t = (t + b - size) / 2; 88 b = t + size; 89 break; 90 } 91 } 92 center(mShutter, l, t, r, b, orientation, rotation, shutter); 93 center(mBackgroundView, l, t, r, b, orientation, rotation, new Rect()); 94 toLeft(mSwitcher, shutter, rotation); 95 toRight(mMenu, shutter, rotation); 96 toRight(mIndicators, shutter, rotation); 97 View retake = findViewById(R.id.btn_retake); 98 if (retake != null) { 99 center(retake, shutter, rotation); 100 View cancel = findViewById(R.id.btn_cancel); 101 toLeft(cancel, shutter, rotation); 102 View done = findViewById(R.id.btn_done); 103 toRight(done, shutter, rotation); 104 } 105 } 106 107 private void center(View v, int l, int t, int r, int b, int orientation, int rotation, Rect result) { 108 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); 109 int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; 110 int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; 111 switch (rotation) { 112 case 0: 113 // phone portrait; controls bottom 114 result.left = (r + l) / 2 - tw / 2 + lp.leftMargin; 115 result.right = (r + l) / 2 + tw / 2 - lp.rightMargin; 116 result.bottom = b - lp.bottomMargin; 117 result.top = b - th + lp.topMargin; 118 break; 119 case 90: 120 // phone landscape: controls right 121 result.right = r - lp.rightMargin; 122 result.left = r - tw + lp.leftMargin; 123 result.top = (b + t) / 2 - th / 2 + lp.topMargin; 124 result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin; 125 break; 126 case 180: 127 // phone upside down: controls top 128 result.left = (r + l) / 2 - tw / 2 + lp.leftMargin; 129 result.right = (r + l) / 2 + tw / 2 - lp.rightMargin; 130 result.top = t + lp.topMargin; 131 result.bottom = t + th - lp.bottomMargin; 132 break; 133 case 270: 134 // reverse landscape: controls left 135 result.left = l + lp.leftMargin; 136 result.right = l + tw - lp.rightMargin; 137 result.top = (b + t) / 2 - th / 2 + lp.topMargin; 138 result.bottom = (b + t) / 2 + th / 2 - lp.bottomMargin; 139 break; 140 } 141 v.layout(result.left, result.top, result.right, result.bottom); 142 } 143 144 private void center(View v, Rect other, int rotation) { 145 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); 146 int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; 147 int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; 148 int cx = (other.left + other.right) / 2; 149 int cy = (other.top + other.bottom) / 2; 150 v.layout(cx - tw / 2 + lp.leftMargin, 151 cy - th / 2 + lp.topMargin, 152 cx + tw / 2 - lp.rightMargin, 153 cy + th / 2 - lp.bottomMargin); 154 } 155 156 private void toLeft(View v, Rect other, int rotation) { 157 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); 158 int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; 159 int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; 160 int cx = (other.left + other.right) / 2; 161 int cy = (other.top + other.bottom) / 2; 162 int l = 0, r = 0, t = 0, b = 0; 163 switch (rotation) { 164 case 0: 165 // portrait, to left of anchor at bottom 166 l = other.left - tw + lp.leftMargin; 167 r = other.left - lp.rightMargin; 168 t = cy - th / 2 + lp.topMargin; 169 b = cy + th / 2 - lp.bottomMargin; 170 break; 171 case 90: 172 // phone landscape: below anchor on right 173 l = cx - tw / 2 + lp.leftMargin; 174 r = cx + tw / 2 - lp.rightMargin; 175 t = other.bottom + lp.topMargin; 176 b = other.bottom + th - lp.bottomMargin; 177 break; 178 case 180: 179 // phone upside down: right of anchor at top 180 l = other.right + lp.leftMargin; 181 r = other.right + tw - lp.rightMargin; 182 t = cy - th / 2 + lp.topMargin; 183 b = cy + th / 2 - lp.bottomMargin; 184 break; 185 case 270: 186 // reverse landscape: above anchor on left 187 l = cx - tw / 2 + lp.leftMargin; 188 r = cx + tw / 2 - lp.rightMargin; 189 t = other.top - th + lp.topMargin; 190 b = other.top - lp.bottomMargin; 191 break; 192 } 193 v.layout(l, t, r, b); 194 } 195 196 private void toRight(View v, Rect other, int rotation) { 197 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams(); 198 int tw = lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; 199 int th = lp.topMargin + v.getMeasuredHeight() + lp.bottomMargin; 200 int cx = (other.left + other.right) / 2; 201 int cy = (other.top + other.bottom) / 2; 202 int l = 0, r = 0, t = 0, b = 0; 203 switch (rotation) { 204 case 0: 205 l = other.right + lp.leftMargin; 206 r = other.right + tw - lp.rightMargin; 207 t = cy - th / 2 + lp.topMargin; 208 b = cy + th / 2 - lp.bottomMargin; 209 break; 210 case 90: 211 l = cx - tw / 2 + lp.leftMargin; 212 r = cx + tw / 2 - lp.rightMargin; 213 t = other.top - th + lp.topMargin; 214 b = other.top - lp.bottomMargin; 215 break; 216 case 180: 217 l = other.left - tw + lp.leftMargin; 218 r = other.left - lp.rightMargin; 219 t = cy - th / 2 + lp.topMargin; 220 b = cy + th / 2 - lp.bottomMargin; 221 break; 222 case 270: 223 l = cx - tw / 2 + lp.leftMargin; 224 r = cx + tw / 2 - lp.rightMargin; 225 t = other.bottom + lp.topMargin; 226 b = other.bottom + th - lp.bottomMargin; 227 break; 228 } 229 v.layout(l, t, r, b); 230 } 231 232 private void topRight(View v, int l, int t, int r, int b) { 233 // layout using the specific margins; the rotation code messes up the others 234 int mt = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_top); 235 int mr = getContext().getResources().getDimensionPixelSize(R.dimen.capture_margin_right); 236 v.layout(r - v.getMeasuredWidth() - mr, t + mt, r - mr, t + mt + v.getMeasuredHeight()); 237 } 238 239 private void adjustBackground() { 240 int rotation = getUnifiedRotation(); 241 // remove current drawable and reset rotation 242 mBackgroundView.setBackgroundDrawable(null); 243 mBackgroundView.setRotationX(0); 244 mBackgroundView.setRotationY(0); 245 // if the switcher background is top aligned we need to flip the background 246 // drawable vertically; if left aligned, flip horizontally 247 switch (rotation) { 248 case 180: 249 mBackgroundView.setRotationX(180); 250 break; 251 case 270: 252 mBackgroundView.setRotationY(180); 253 break; 254 default: 255 break; 256 } 257 mBackgroundView.setBackgroundResource(R.drawable.switcher_bg); 258 } 259 260 } 261