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