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.content.Context;
20import android.graphics.Rect;
21import android.util.AttributeSet;
22import android.view.View;
23import android.widget.FrameLayout;
24
25import com.android.camera2.R;
26
27public 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