| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.camera.ui; |
| |
| import android.annotation.TargetApi; |
| import android.content.Context; |
| import android.graphics.Canvas; |
| import android.graphics.Matrix; |
| import android.graphics.Rect; |
| import android.util.AttributeSet; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewParent; |
| |
| import com.android.gallery3d.common.ApiHelper; |
| import com.android.gallery3d.util.MotionEventHelper; |
| |
| // A RotateLayout is designed to display a single item and provides the |
| // capabilities to rotate the item. |
| public class RotateLayout extends ViewGroup implements Rotatable { |
| @SuppressWarnings("unused") |
| private static final String TAG = "RotateLayout"; |
| private int mOrientation; |
| private Matrix mMatrix = new Matrix(); |
| protected View mChild; |
| |
| public RotateLayout(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| // The transparent background here is a workaround of the render issue |
| // happened when the view is rotated as the device's orientation |
| // changed. The view looks fine in landscape. After rotation, the view |
| // is invisible. |
| setBackgroundResource(android.R.color.transparent); |
| } |
| |
| @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) |
| @Override |
| protected void onFinishInflate() { |
| mChild = getChildAt(0); |
| if (ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) { |
| mChild.setPivotX(0); |
| mChild.setPivotY(0); |
| } |
| } |
| |
| @Override |
| protected void onLayout( |
| boolean change, int left, int top, int right, int bottom) { |
| int width = right - left; |
| int height = bottom - top; |
| switch (mOrientation) { |
| case 0: |
| case 180: |
| mChild.layout(0, 0, width, height); |
| break; |
| case 90: |
| case 270: |
| mChild.layout(0, 0, height, width); |
| break; |
| } |
| } |
| |
| @Override |
| public boolean dispatchTouchEvent(MotionEvent event) { |
| if (!ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) { |
| final int w = getMeasuredWidth(); |
| final int h = getMeasuredHeight(); |
| switch (mOrientation) { |
| case 0: |
| mMatrix.setTranslate(0, 0); |
| break; |
| case 90: |
| mMatrix.setTranslate(0, -h); |
| break; |
| case 180: |
| mMatrix.setTranslate(-w, -h); |
| break; |
| case 270: |
| mMatrix.setTranslate(-w, 0); |
| break; |
| } |
| mMatrix.postRotate(mOrientation); |
| event = MotionEventHelper.transformEvent(event, mMatrix); |
| } |
| return super.dispatchTouchEvent(event); |
| } |
| |
| @Override |
| protected void dispatchDraw(Canvas canvas) { |
| if (ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) { |
| super.dispatchDraw(canvas); |
| } else { |
| canvas.save(); |
| int w = getMeasuredWidth(); |
| int h = getMeasuredHeight(); |
| switch (mOrientation) { |
| case 0: |
| canvas.translate(0, 0); |
| break; |
| case 90: |
| canvas.translate(0, h); |
| break; |
| case 180: |
| canvas.translate(w, h); |
| break; |
| case 270: |
| canvas.translate(w, 0); |
| break; |
| } |
| canvas.rotate(-mOrientation, 0, 0); |
| super.dispatchDraw(canvas); |
| canvas.restore(); |
| } |
| } |
| |
| @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) |
| @Override |
| protected void onMeasure(int widthSpec, int heightSpec) { |
| int w = 0, h = 0; |
| switch(mOrientation) { |
| case 0: |
| case 180: |
| measureChild(mChild, widthSpec, heightSpec); |
| w = mChild.getMeasuredWidth(); |
| h = mChild.getMeasuredHeight(); |
| break; |
| case 90: |
| case 270: |
| measureChild(mChild, heightSpec, widthSpec); |
| w = mChild.getMeasuredHeight(); |
| h = mChild.getMeasuredWidth(); |
| break; |
| } |
| setMeasuredDimension(w, h); |
| |
| if (ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) { |
| switch (mOrientation) { |
| case 0: |
| mChild.setTranslationX(0); |
| mChild.setTranslationY(0); |
| break; |
| case 90: |
| mChild.setTranslationX(0); |
| mChild.setTranslationY(h); |
| break; |
| case 180: |
| mChild.setTranslationX(w); |
| mChild.setTranslationY(h); |
| break; |
| case 270: |
| mChild.setTranslationX(w); |
| mChild.setTranslationY(0); |
| break; |
| } |
| mChild.setRotation(-mOrientation); |
| } |
| } |
| |
| @Override |
| public boolean shouldDelayChildPressedState() { |
| return false; |
| } |
| |
| // Rotate the view counter-clockwise |
| @Override |
| public void setOrientation(int orientation, boolean animation) { |
| orientation = orientation % 360; |
| if (mOrientation == orientation) return; |
| mOrientation = orientation; |
| requestLayout(); |
| } |
| |
| public int getOrientation() { |
| return mOrientation; |
| } |
| |
| @Override |
| public ViewParent invalidateChildInParent(int[] location, Rect r) { |
| if (!ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES && mOrientation != 0) { |
| // The workaround invalidates the entire rotate layout. After |
| // rotation, the correct area to invalidate may be larger than the |
| // size of the child. Ex: ListView. There is no way to invalidate |
| // only the necessary area. |
| r.set(0, 0, getWidth(), getHeight()); |
| } |
| return super.invalidateChildInParent(location, r); |
| } |
| } |