Skip to content

Commit

Permalink
Better auto-focus
Browse files Browse the repository at this point in the history
This simplifies the API by removing focusMode and introducing autoFocus.
Pictures are now taken right after auto-focus.  Also remove external
camera support as there is no easy way to support it for API Level <21.

The demo app now has a button to switch camera.

Change-Id: If978959d2095632c332d17ab7f99e6ed18d82057
  • Loading branch information
yaraki committed Jun 6, 2016
1 parent d682b03 commit 7faceeb
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

Expand Down Expand Up @@ -100,6 +104,12 @@ protected void onCreate(Bundle savedInstanceState) {
if (takePicture != null) {
takePicture.setOnClickListener(mOnClickListener);
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
}
}

@Override
Expand Down Expand Up @@ -167,6 +177,26 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.switch_camera:
if (mCameraView != null) {
int facing = mCameraView.getFacing();
mCameraView.setFacing(facing == CameraView.FACING_FRONT ?
CameraView.FACING_BACK : CameraView.FACING_FRONT);
}
break;
}
return false;
}

private Handler getBackgroundHandler() {
if (mBackgroundHandler == null) {
HandlerThread thread = new HandlerThread("background");
Expand Down
22 changes: 22 additions & 0 deletions demo/src/main/res/drawable/ic_switch_camera.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M20,4h-3.17L15,2L9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM15,15.5L15,13L9,13v2.5L5.5,12 9,8.5L9,11h6L15,8.5l3.5,3.5 -3.5,3.5z"/>
</vector>
22 changes: 15 additions & 7 deletions demo/src/main/res/layout/include_camera.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.google.android.cameraview.CameraView
android:id="@+id/camera"
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:facing="back"
app:focusMode="continuousPicture"/>
android:layout_height="match_parent">

<com.google.android.cameraview.CameraView
android:id="@+id/camera"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"/>

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>

</FrameLayout>
24 changes: 24 additions & 0 deletions demo/src/main/res/menu/main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/switch_camera"
android:icon="@drawable/ic_switch_camera"
android:title="@string/switch_camera"
app:showAsAction="ifRoom"/>

</menu>
1 change: 1 addition & 0 deletions demo/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@
<string name="storage_permission_confirmation">This app saves taken photos to external storage.</string>
<string name="storage_permission_not_granted">The app does not have permission to save a photo.</string>
<string name="picture_taken">Picture taken</string>
<string name="switch_camera">Switch camera</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ public void check(View view, NoMatchingViewException noViewFoundException) {
CameraView cameraView = (CameraView) view;
AspectRatio ratio = cameraView.getAspectRatio();
assertThat(ratio, is(notNullValue()));
Set<AspectRatio> ratios = cameraView.getSupportedAspectRatios();
assertThat(ratios.size(), is(greaterThanOrEqualTo(1)));
assertThat(ratios, hasItem(ratio));
if (ratios.size() == 1) {
return;
}
// Pick one ratio to change to
for (AspectRatio r : ratios) {
if (!r.equals(ratio)) {
ratio = r;
break;
}
}
assert ratio != null;
cameraView.setAspectRatio(ratio);
assertThat(cameraView.getAspectRatio(), is(equalTo(ratio)));
}
});
}
Expand Down Expand Up @@ -163,16 +179,18 @@ public void check(View view, NoMatchingViewException noViewFoundException) {
}

@Test
public void testFocusMode() {
public void testAutoFocus() {
onView(withId(R.id.camera))
.check(new ViewAssertion() {
@Override
public void check(View view, NoMatchingViewException noViewFoundException) {
CameraView cameraView = (CameraView) view;
assertThat(cameraView.getFocusMode(), is(CameraView.FOCUS_MODE_OFF));
cameraView.setFocusMode(CameraView.FOCUS_MODE_CONTINUOUS_PICTURE);
assertThat(cameraView.getFocusMode(),
is(CameraView.FOCUS_MODE_CONTINUOUS_PICTURE));
// This can fail on devices without auto-focus support
assertThat(cameraView.getAutoFocus(), is(true));
cameraView.setAutoFocus(false);
assertThat(cameraView.getAutoFocus(), is(false));
cameraView.setAutoFocus(true);
assertThat(cameraView.getAutoFocus(), is(true));
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import android.view.TextureView;

import java.util.Set;

abstract class CameraViewImpl {

protected final Callback mCallback;
Expand All @@ -34,13 +36,15 @@ public CameraViewImpl(Callback callback) {

abstract boolean isCameraOpened();

abstract Set<AspectRatio> getSupportedAspectRatios();

abstract void setAspectRatio(AspectRatio ratio);

abstract AspectRatio getAspectRatio();

abstract void setFocusMode(int focusMode);
abstract void setAutoFocus(boolean autoFocus);

abstract int getFocusMode();
abstract boolean getAutoFocus();

abstract void setFacing(int facing);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,7 @@

interface Constants {

int FOCUS_MODE_OFF = 0;
int FOCUS_MODE_AUTO = 1;
int FOCUS_MODE_MACRO = 2;
int FOCUS_MODE_CONTINUOUS_PICTURE = 3;
int FOCUS_MODE_CONTINUOUS_VIDEO = 4;
int FOCUS_MODE_EDOF = 5;

int FACING_BACK = 0;
int FACING_FRONT = 1;
int FACING_EXTERNAL = 2;

}
77 changes: 60 additions & 17 deletions library/src/main/camera1/com/google/android/cameraview/Camera1.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.view.TextureView;

import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;

Expand Down Expand Up @@ -49,7 +50,7 @@ class Camera1 extends CameraViewImpl {

private boolean mShowingPreview;

private int mFocusMode;
private boolean mAutoFocus;

private int mFacing;

Expand Down Expand Up @@ -141,6 +142,11 @@ boolean isCameraOpened() {
return mCamera != null;
}

@Override
Set<AspectRatio> getSupportedAspectRatios() {
return mPreviewSizes.ratios();
}

@Override
void setAspectRatio(AspectRatio ratio) {
if (mAspectRatio == null || !isCameraOpened()) {
Expand All @@ -163,29 +169,30 @@ AspectRatio getAspectRatio() {
}

@Override
void setFocusMode(int focusMode) {
if (mFocusMode != focusMode) {
mFocusMode = focusMode;
if (mCamera != null) {
mCameraParameters.setFocusMode(Camera1Constants.convertFocusMode(focusMode));
mCamera.setParameters(mCameraParameters);
}
void setAutoFocus(boolean autoFocus) {
if (mAutoFocus == autoFocus) {
return;
}
if (setAutoFocusInternal(autoFocus)) {
mCamera.setParameters(mCameraParameters);
}
}

@Override
int getFocusMode() {
return mFocusMode;
boolean getAutoFocus() {
String focusMode = mCameraParameters.getFocusMode();
return focusMode != null && focusMode.contains("continuous");
}

@Override
void setFacing(int facing) {
if (mFacing != facing) {
mFacing = facing;
if (mCamera != null) {
stop();
start();
}
if (mFacing == facing) {
return;
}
mFacing = facing;
if (isCameraOpened()) {
stop();
start();
}
}

Expand All @@ -199,6 +206,20 @@ void takePicture() {
if (!isCameraOpened()) {
throw new IllegalStateException("Camera is not ready. Call start() before takePicture().");
}
if (getAutoFocus()) {
mCamera.cancelAutoFocus();
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
takePictureInternal();
}
});
} else {
takePictureInternal();
}
}

private void takePictureInternal() {
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Expand Down Expand Up @@ -285,7 +306,7 @@ private void adjustCameraParameters() {
mCameraParameters.setPreviewSize(size.getWidth(), size.getHeight());
mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation));
mCameraParameters.setFocusMode(Camera1Constants.convertFocusMode(mFocusMode));
setAutoFocusInternal(mAutoFocus);
mCamera.setParameters(mCameraParameters);
if (mShowingPreview) {
mCamera.startPreview();
Expand Down Expand Up @@ -334,4 +355,26 @@ private int calcCameraRotation(int rotation) {
}
}

/**
* @return {@code true} if {@link #mCameraParameters} was modified.
*/
private boolean setAutoFocusInternal(boolean autoFocus) {
mAutoFocus = autoFocus;
if (isCameraOpened()) {
final List<String> modes = mCameraParameters.getSupportedFocusModes();
if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
} else {
mCameraParameters.setFocusMode(modes.get(0));
}
return true;
} else {
return false;
}
}

}
Loading

0 comments on commit 7faceeb

Please sign in to comment.