Skip to content

Commit

Permalink
Better handling for display orientation
Browse files Browse the repository at this point in the history
Externalize all tasks related to display orientation into
DisplayOrientationDetector.

Change-Id: I5d7c52f4912e1e5065505d4c9e73cce915c4408d
  • Loading branch information
yaraki committed Jun 3, 2016
1 parent a4fe117 commit d682b03
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ public CameraViewImpl(Callback callback) {

abstract AspectRatio getAspectRatio();

abstract int getDisplayOrientation();

abstract void setFocusMode(int focusMode);

abstract int getFocusMode();
Expand All @@ -50,7 +48,7 @@ public CameraViewImpl(Callback callback) {

abstract void takePicture();

abstract void setOrientation(int orientation);
abstract void setDisplayOrientation(int displayOrientation);

interface Callback {

Expand Down
76 changes: 14 additions & 62 deletions library/src/main/camera1/com/google/android/cameraview/Camera1.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,9 @@

package com.google.android.cameraview;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.view.Surface;
import android.view.TextureView;
import android.view.WindowManager;

import java.io.IOException;
import java.util.Set;
Expand All @@ -34,10 +31,6 @@ class Camera1 extends CameraViewImpl {

private static final AspectRatio DEFAULT_ASPECT_RATIO = AspectRatio.of(4, 3);

private static final String TAG = "Camera1";

private final Context mContext;

private int mCameraId;

private Camera mCamera;
Expand All @@ -54,15 +47,13 @@ class Camera1 extends CameraViewImpl {

private AspectRatio mAspectRatio;

private int mDisplayOrientation;

private boolean mShowingPreview;

private int mFocusMode;

private int mFacing;

private int mOrientation;
private int mDisplayOrientation;

private static class PreviewInfo {
SurfaceTexture surface;
Expand Down Expand Up @@ -108,9 +99,8 @@ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};

public Camera1(Context context, Callback callback) {
public Camera1(Callback callback) {
super(callback);
mContext = context;
}

@Override
Expand Down Expand Up @@ -172,11 +162,6 @@ AspectRatio getAspectRatio() {
return mAspectRatio;
}

@Override
int getDisplayOrientation() {
return mDisplayOrientation;
}

@Override
void setFocusMode(int focusMode) {
if (mFocusMode != focusMode) {
Expand Down Expand Up @@ -224,16 +209,13 @@ public void onPictureTaken(byte[] data, Camera camera) {
}

@Override
void setOrientation(int orientation) {
if (mOrientation != orientation) {
mOrientation = orientation;
if (isCameraOpened()) {
calcRotation(mCameraParameters);
mCamera.setParameters(mCameraParameters);

mDisplayOrientation = calcDisplayOrientation();
mCamera.setDisplayOrientation(mDisplayOrientation);
}
void setDisplayOrientation(int displayOrientation) {
mDisplayOrientation = displayOrientation;
if (isCameraOpened()) {
int cameraRotation = calcCameraRotation(displayOrientation);
mCameraParameters.setRotation(cameraRotation);
mCamera.setParameters(mCameraParameters);
mCamera.setDisplayOrientation(cameraRotation);
}
}

Expand Down Expand Up @@ -272,9 +254,7 @@ private void openCamera() {
mAspectRatio = DEFAULT_ASPECT_RATIO;
}
adjustCameraParameters();
// Display orientation
mDisplayOrientation = calcDisplayOrientation();
mCamera.setDisplayOrientation(mDisplayOrientation);
mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation));
mCallback.onCameraOpened();
}

Expand Down Expand Up @@ -304,7 +284,7 @@ private void adjustCameraParameters() {
}
mCameraParameters.setPreviewSize(size.getWidth(), size.getHeight());
mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
calcRotation(mCameraParameters);
mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation));
mCameraParameters.setFocusMode(Camera1Constants.convertFocusMode(mFocusMode));
mCamera.setParameters(mCameraParameters);
if (mShowingPreview) {
Expand All @@ -313,16 +293,6 @@ private void adjustCameraParameters() {
}
}

private void calcRotation(Camera.Parameters parameters) {
int rotation;
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotation = (mCameraInfo.orientation - mOrientation + 360) % 360;
} else { // back-facing camera
rotation = (mCameraInfo.orientation + mOrientation) % 360;
}
parameters.setRotation(rotation);
}

@SuppressWarnings("SuspiciousNameCombination")
private Size chooseOptimalSize(SortedSet<Size> sizes) {
if (mPreviewInfo.width == 0 || mPreviewInfo.height == 0) { // Not yet laid out
Expand Down Expand Up @@ -356,29 +326,11 @@ private void releaseCamera() {
}
}

private int calcDisplayOrientation() {
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
int rotation = manager.getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
private int calcCameraRotation(int rotation) {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
int result = (mCameraInfo.orientation + degrees) % 360;
return (360 - result) % 360; // compensate the mirror
return (360 - (mCameraInfo.orientation + rotation) % 360) % 360;
} else { // back-facing
return (mCameraInfo.orientation - degrees + 360) % 360;
return (mCameraInfo.orientation - rotation + 360) % 360;
}
}

Expand Down
43 changes: 21 additions & 22 deletions library/src/main/java/com/google/android/cameraview/CameraView.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.OrientationEventListener;
import android.view.TextureView;
import android.widget.FrameLayout;

Expand Down Expand Up @@ -62,9 +61,9 @@ public class CameraView extends FrameLayout {

private boolean mAdjustViewBounds;

private TextureView mTextureView;
private final TextureView mTextureView;

private OrientationEventListener mOrientationEventListener;
private final DisplayOrientationDetector mDisplayOrientationDetector;

public CameraView(Context context) {
this(context, null);
Expand All @@ -80,9 +79,9 @@ public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
// Internal setup
mCallbacks = new CallbackBridge();
if (Build.VERSION.SDK_INT < 21) {
mImpl = new Camera1(context, mCallbacks);
mImpl = new Camera1(mCallbacks);
} else {
mImpl = new Camera1(context, mCallbacks); // TODO: Implement Camera2 and replace this
mImpl = new Camera1(mCallbacks); // TODO: Implement Camera2 and replace this
}
// View content
inflate(context, R.layout.camera_view, this);
Expand All @@ -95,24 +94,27 @@ public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
setFocusMode(a.getInt(R.styleable.CameraView_focusMode, FOCUS_MODE_OFF));
setFacing(a.getInt(R.styleable.CameraView_facing, FACING_BACK));
a.recycle();
// Orientation listener
mOrientationEventListener = new OrientationEventListener(context) {
private int mLastOrientation;
// Display orientation detector
mDisplayOrientationDetector = new DisplayOrientationDetector(context) {
@Override
public void onOrientationChanged(int orientation) {
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
return;
}
// Round the value to one of 0, 90, 180, and 270
orientation = ((orientation + 45) / 90 * 90) % 360;
if (mLastOrientation != orientation) {
mLastOrientation = orientation;
mImpl.setOrientation(orientation);
}
public void onDisplayOrientationChanged(int displayOrientation) {
mImpl.setDisplayOrientation(displayOrientation);
}
};
}

@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mDisplayOrientationDetector.enable(getDisplay());
}

@Override
protected void onDetachedFromWindow() {
mDisplayOrientationDetector.disable();
super.onDetachedFromWindow();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Handle android:adjustViewBounds
Expand Down Expand Up @@ -152,8 +154,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
AspectRatio ratio = getAspectRatio();
int orientation = mImpl.getDisplayOrientation();
if (orientation == 90 || orientation == 270) {
if (mDisplayOrientationDetector.getLastKnownDisplayOrientation() % 180 == 0) {
ratio = ratio.inverse();
}
assert ratio != null;
Expand All @@ -175,7 +176,6 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
* {@link Activity#onResume()}.
*/
public void start() {
mOrientationEventListener.enable();
mImpl.start();
}

Expand All @@ -185,7 +185,6 @@ public void start() {
*/
public void stop() {
mImpl.stop();
mOrientationEventListener.disable();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2016 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.google.android.cameraview;

import android.content.Context;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.OrientationEventListener;
import android.view.Surface;


/**
* Monitors the value returned from {@link Display#getRotation()}.
*/
abstract class DisplayOrientationDetector {

private final OrientationEventListener mOrientationEventListener;

/** Mapping from Surface.Rotation_n to degrees. */
private static final SparseIntArray DISPLAY_ORIENTATIONS = new SparseIntArray();

static {
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0);
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90);
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_180, 180);
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_270, 270);
}

private Display mDisplay;

private int mLastKnownDisplayOrientation = 0;

public DisplayOrientationDetector(Context context) {
mOrientationEventListener = new OrientationEventListener(context) {

/** This is either Surface.Rotation_0, _90, _180, _270, or -1 (invalid). */
private int mLastKnownRotation = -1;

@Override
public void onOrientationChanged(int orientation) {
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN ||
mDisplay == null) {
return;
}
final int rotation = mDisplay.getRotation();
if (mLastKnownRotation != rotation) {
mLastKnownRotation = rotation;
dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(rotation));
}
}
};
}

public void enable(Display display) {
mDisplay = display;
mOrientationEventListener.enable();
// Immediately dispatch the first callback
dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(display.getRotation()));
}

public void disable() {
mOrientationEventListener.disable();
mDisplay = null;
}

public int getLastKnownDisplayOrientation() {
return mLastKnownDisplayOrientation;
}

private void dispatchOnDisplayOrientationChanged(int displayOrientation) {
mLastKnownDisplayOrientation = displayOrientation;
onDisplayOrientationChanged(displayOrientation);
}

/**
* Called when display orientation is changed.
*
* @param displayOrientation One of 0, 90, 180, and 270.
*/
public abstract void onDisplayOrientationChanged(int displayOrientation);

}

0 comments on commit d682b03

Please sign in to comment.