1c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li/*
2c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * Copyright (C) 2010 The Android Open Source Project
3c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li *
4c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * Licensed under the Apache License, Version 2.0 (the "License");
5c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * you may not use this file except in compliance with the License.
6c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * You may obtain a copy of the License at
7c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li *
8c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li *      http://www.apache.org/licenses/LICENSE-2.0
9c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li *
10c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * Unless required by applicable law or agreed to in writing, software
11c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * distributed under the License is distributed on an "AS IS" BASIS,
12c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * See the License for the specific language governing permissions and
14c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li * limitations under the License.
15c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li */
16c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
17c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Lipackage com.android.camera.ui;
18c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
19394076fcefbe61033d203da977416ffde86bd8baWu-cheng Liimport android.annotation.TargetApi;
20c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Liimport android.content.Context;
21ada86b7979942a532c99be9852da82e09512fa22Ahbong Changimport android.graphics.Canvas;
22cce55282e5ae2414811f2e416961f318f553c400Ahbong Changimport android.graphics.Matrix;
23394076fcefbe61033d203da977416ffde86bd8baWu-cheng Liimport android.graphics.Rect;
24c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Liimport android.util.AttributeSet;
25cce55282e5ae2414811f2e416961f318f553c400Ahbong Changimport android.view.MotionEvent;
26c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Liimport android.view.View;
27c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Liimport android.view.ViewGroup;
28394076fcefbe61033d203da977416ffde86bd8baWu-cheng Liimport android.view.ViewParent;
29c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
30394076fcefbe61033d203da977416ffde86bd8baWu-cheng Liimport com.android.gallery3d.common.ApiHelper;
31cce55282e5ae2414811f2e416961f318f553c400Ahbong Changimport com.android.gallery3d.util.MotionEventHelper;
32cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang
33c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li// A RotateLayout is designed to display a single item and provides the
34c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li// capabilities to rotate the item.
3594ca8baae7e6e3885d895c095890eabf30d922e2Chih-yu Huangpublic class RotateLayout extends ViewGroup implements Rotatable {
36913f3784d368a5e11fee5d5db2c355ef832685daWu-cheng Li    @SuppressWarnings("unused")
37750173a4d20f1e8d6607edb3ada6be5166d0cd82Wu-cheng Li    private static final String TAG = "RotateLayout";
38c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    private int mOrientation;
39cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang    private Matrix mMatrix = new Matrix();
40e75e33cd3de39f1961d3fac8e7a51d126260de45Wu-cheng Li    protected View mChild;
41c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
42c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    public RotateLayout(Context context, AttributeSet attrs) {
43c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        super(context, attrs);
44d4832351874aa6eb2cd5e312c21bd4ec607ff3a4Wu-cheng Li        // The transparent background here is a workaround of the render issue
45d4832351874aa6eb2cd5e312c21bd4ec607ff3a4Wu-cheng Li        // happened when the view is rotated as the device's orientation
46d4832351874aa6eb2cd5e312c21bd4ec607ff3a4Wu-cheng Li        // changed. The view looks fine in landscape. After rotation, the view
47d4832351874aa6eb2cd5e312c21bd4ec607ff3a4Wu-cheng Li        // is invisible.
48d4832351874aa6eb2cd5e312c21bd4ec607ff3a4Wu-cheng Li        setBackgroundResource(android.R.color.transparent);
49c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    }
50c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
51394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li    @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
52c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    @Override
53c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    protected void onFinishInflate() {
54c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        mChild = getChildAt(0);
55394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        if (ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) {
56394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            mChild.setPivotX(0);
57394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            mChild.setPivotY(0);
58394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        }
59c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    }
60c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
61c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    @Override
62c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    protected void onLayout(
63c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            boolean change, int left, int top, int right, int bottom) {
64c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        int width = right - left;
65c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        int height = bottom - top;
66c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        switch (mOrientation) {
67c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 0:
68c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 180:
69c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                mChild.layout(0, 0, width, height);
70c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                break;
71c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 90:
72c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 270:
73c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                mChild.layout(0, 0, height, width);
74c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                break;
75c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        }
76c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    }
77c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
78c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    @Override
79cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang    public boolean dispatchTouchEvent(MotionEvent event) {
80394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        if (!ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) {
81394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            final int w = getMeasuredWidth();
82394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            final int h = getMeasuredHeight();
83394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            switch (mOrientation) {
84394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 0:
85394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mMatrix.setTranslate(0, 0);
86394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
87394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 90:
88394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mMatrix.setTranslate(0, -h);
89394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
90394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 180:
91394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mMatrix.setTranslate(-w, -h);
92394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
93394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 270:
94394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mMatrix.setTranslate(-w, 0);
95394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
96394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            }
97394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            mMatrix.postRotate(mOrientation);
98394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            event = MotionEventHelper.transformEvent(event, mMatrix);
99cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang        }
100cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang        return super.dispatchTouchEvent(event);
101cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang    }
102cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang
103cce55282e5ae2414811f2e416961f318f553c400Ahbong Chang    @Override
104ada86b7979942a532c99be9852da82e09512fa22Ahbong Chang    protected void dispatchDraw(Canvas canvas) {
105394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        if (ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) {
106394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            super.dispatchDraw(canvas);
107394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        } else {
108394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            canvas.save();
109394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            int w = getMeasuredWidth();
110394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            int h = getMeasuredHeight();
111394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            switch (mOrientation) {
112394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 0:
113394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    canvas.translate(0, 0);
114394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
115394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 90:
116394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    canvas.translate(0, h);
117394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
118394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 180:
119394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    canvas.translate(w, h);
120394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
121394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 270:
122394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    canvas.translate(w, 0);
123394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
124394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            }
125394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            canvas.rotate(-mOrientation, 0, 0);
126394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            super.dispatchDraw(canvas);
127394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            canvas.restore();
128ada86b7979942a532c99be9852da82e09512fa22Ahbong Chang        }
129ada86b7979942a532c99be9852da82e09512fa22Ahbong Chang    }
130ada86b7979942a532c99be9852da82e09512fa22Ahbong Chang
131394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li    @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
132ada86b7979942a532c99be9852da82e09512fa22Ahbong Chang    @Override
133c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    protected void onMeasure(int widthSpec, int heightSpec) {
134750173a4d20f1e8d6607edb3ada6be5166d0cd82Wu-cheng Li        int w = 0, h = 0;
135c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        switch(mOrientation) {
136c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 0:
137c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 180:
138c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                measureChild(mChild, widthSpec, heightSpec);
139750173a4d20f1e8d6607edb3ada6be5166d0cd82Wu-cheng Li                w = mChild.getMeasuredWidth();
140750173a4d20f1e8d6607edb3ada6be5166d0cd82Wu-cheng Li                h = mChild.getMeasuredHeight();
141c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                break;
142c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 90:
143c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li            case 270:
144c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                measureChild(mChild, heightSpec, widthSpec);
145750173a4d20f1e8d6607edb3ada6be5166d0cd82Wu-cheng Li                w = mChild.getMeasuredHeight();
146750173a4d20f1e8d6607edb3ada6be5166d0cd82Wu-cheng Li                h = mChild.getMeasuredWidth();
147c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li                break;
148c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        }
149750173a4d20f1e8d6607edb3ada6be5166d0cd82Wu-cheng Li        setMeasuredDimension(w, h);
150394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li
151394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        if (ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) {
152394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            switch (mOrientation) {
153394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 0:
154394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationX(0);
155394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationY(0);
156394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
157394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 90:
158394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationX(0);
159394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationY(h);
160394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
161394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 180:
162394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationX(w);
163394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationY(h);
164394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
165394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                case 270:
166394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationX(w);
167394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    mChild.setTranslationY(0);
168394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li                    break;
169394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            }
170394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            mChild.setRotation(-mOrientation);
171394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        }
172c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    }
173c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li
17476aabec658bfa46ce1cfa1974ed6b4cdff356ac4akahuang    @Override
17576aabec658bfa46ce1cfa1974ed6b4cdff356ac4akahuang    public boolean shouldDelayChildPressedState() {
17676aabec658bfa46ce1cfa1974ed6b4cdff356ac4akahuang        return false;
17776aabec658bfa46ce1cfa1974ed6b4cdff356ac4akahuang    }
17876aabec658bfa46ce1cfa1974ed6b4cdff356ac4akahuang
179c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    // Rotate the view counter-clockwise
1802865863f6a1887bda17e0a58a6a0f3aaac237cb6Angus Kong    @Override
1812865863f6a1887bda17e0a58a6a0f3aaac237cb6Angus Kong    public void setOrientation(int orientation, boolean animation) {
182c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        orientation = orientation % 360;
183c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        if (mOrientation == orientation) return;
184c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        mOrientation = orientation;
185c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li        requestLayout();
186c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li    }
187394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li
18838a6c24485d36651b93d5935bfbaf3cd367885e7Michael Kolb    public int getOrientation() {
18938a6c24485d36651b93d5935bfbaf3cd367885e7Michael Kolb        return mOrientation;
19038a6c24485d36651b93d5935bfbaf3cd367885e7Michael Kolb    }
19138a6c24485d36651b93d5935bfbaf3cd367885e7Michael Kolb
192394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li    @Override
193394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li    public ViewParent invalidateChildInParent(int[] location, Rect r) {
194394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        if (!ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES && mOrientation != 0) {
195394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            // The workaround invalidates the entire rotate layout. After
196394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            // rotation, the correct area to invalidate may be larger than the
197394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            // size of the child. Ex: ListView. There is no way to invalidate
198394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            // only the necessary area.
199394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li            r.set(0, 0, getWidth(), getHeight());
200394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        }
201394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li        return super.invalidateChildInParent(location, r);
202394076fcefbe61033d203da977416ffde86bd8baWu-cheng Li    }
203c5e37cbb96b8284203560c51dd5f41c705a21f58Wu-cheng Li}
204