DownOL 软件仓库– 软件下载,字节世界与新知

App中CameraView

发表于:2024-05-17 作者:创始人
编辑最后更新 2024年05月17日,首先来看下cameraview的源码/** Copyright (C) 2016 The Android Open Source Project** Licensed under the Apache

首先来看下cameraview的源码

/** 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.app.Activity;import android.content.Context;import android.content.res.TypedArray;import android.os.Build;import android.os.Parcel;import android.os.Parcelable;import android.support.annotation.IntDef;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.support.v4.os.ParcelableCompat;import android.support.v4.os.ParcelableCompatCreatorCallbacks;import android.support.v4.view.ViewCompat;import android.util.AttributeSet;import android.widget.FrameLayout;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.util.ArrayList;import java.util.Set;public class CameraView extends FrameLayout {/** The camera device faces the opposite direction as the device's screen. */public static final int FACING_BACK = Constants.FACING_BACK;/** The camera device faces the same direction as the device's screen. */public static final int FACING_FRONT = Constants.FACING_FRONT;/** Direction the camera faces relative to device screen. */@IntDef({FACING_BACK, FACING_FRONT})@Retention(RetentionPolicy.SOURCE)public @interface Facing {}/** Flash will not be fired. */public static final int FLASH_OFF = Constants.FLASH_OFF;/** Flash will always be fired during snapshot. */public static final int FLASH_ON = Constants.FLASH_ON;/** Constant emission of light during preview, auto-focus and snapshot. */public static final int FLASH_TORCH = Constants.FLASH_TORCH;/** Flash will be fired automatically when required. */public static final int FLASH_AUTO = Constants.FLASH_AUTO;/** Flash will be fired in red-eye reduction mode. */public static final int FLASH_RED_EYE = Constants.FLASH_RED_EYE;/** The mode for for the camera device's flash control */@IntDef({FLASH_OFF, FLASH_ON, FLASH_TORCH, FLASH_AUTO, FLASH_RED_EYE})public @interface Flash {}CameraViewImpl mImpl; private final CallbackBridge mCallbacks; private boolean mAdjustViewBounds; private final DisplayOrientationDetector mDisplayOrientationDetector; public CameraView(Context context) {this(context, null);}public CameraView(Context context, AttributeSet attrs) {this(context, attrs, 0);}@SuppressWarnings("WrongConstant")public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr); if (isInEditMode()){mCallbacks = null;mDisplayOrientationDetector = null; return;}// Internal setupfinal PreviewImpl preview = createPreviewImpl(context);mCallbacks = new CallbackBridge(); if (Build.VERSION.SDK_INT < 21) {mImpl = new Camera1(mCallbacks, preview);} else if (Build.VERSION.SDK_INT < 23) {mImpl = new Camera2(mCallbacks, preview, context);} else {mImpl = new Camera2Api23(mCallbacks, preview, context);}// AttributesTypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr,R.style.Widget_CameraView);mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false);setFacing(a.getInt(R.styleable.CameraView_facing, FACING_BACK));String aspectRatio = a.getString(R.styleable.CameraView_aspectRatio); if (aspectRatio != null) {setAspectRatio(AspectRatio.parse(aspectRatio));} else {setAspectRatio(Constants.DEFAULT_ASPECT_RATIO);}setAutoFocus(a.getBoolean(R.styleable.CameraView_autoFocus, true));setFlash(a.getInt(R.styleable.CameraView_flash, Constants.FLASH_AUTO));a.recycle();// Display orientation detectormDisplayOrientationDetector = new DisplayOrientationDetector(context) {@Overridepublic void onDisplayOrientationChanged(int displayOrientation) {mImpl.setDisplayOrientation(displayOrientation);}};}@NonNullprivate PreviewImpl createPreviewImpl(Context context) {PreviewImpl preview; if (Build.VERSION.SDK_INT < 14) {preview = new SurfaceViewPreview(context, this);} else {preview = new TextureViewPreview(context, this);}return preview;}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow(); if (!isInEditMode()) {mDisplayOrientationDetector.enable(ViewCompat.getDisplay(this));}}@Overrideprotected void onDetachedFromWindow() {if (!isInEditMode()) {mDisplayOrientationDetector.disable();}super.onDetachedFromWindow();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {if (isInEditMode()){super.onMeasure(widthMeasureSpec, heightMeasureSpec); return;}// Handle android:adjustViewBoundsif (mAdjustViewBounds) {if (!isCameraOpened()) {mCallbacks.reserveRequestLayoutOnOpen(); super.onMeasure(widthMeasureSpec, heightMeasureSpec); return;}final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {final AspectRatio ratio = getAspectRatio(); assert ratio != null; int height = (int) (MeasureSpec.getSize(widthMeasureSpec) * ratio.toFloat()); if (heightMode == MeasureSpec.AT_MOST) {height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));}super.onMeasure(widthMeasureSpec,MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));} else if (widthMode != MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {final AspectRatio ratio = getAspectRatio(); assert ratio != null; int width = (int) (MeasureSpec.getSize(heightMeasureSpec) * ratio.toFloat()); if (widthMode == MeasureSpec.AT_MOST) {width = Math.min(width, MeasureSpec.getSize(widthMeasureSpec));}super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),heightMeasureSpec);} else {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}} else {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}// Measure the TextureViewint width = getMeasuredWidth(); int height = getMeasuredHeight();AspectRatio ratio = getAspectRatio(); if (mDisplayOrientationDetector.getLastKnownDisplayOrientation() % 180 == 0) {ratio = ratio.inverse();}assert ratio != null; if (height < width * ratio.getY() / ratio.getX()) {mImpl.getView().measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(width * ratio.getY() / ratio.getX(),MeasureSpec.EXACTLY));} else {mImpl.getView().measure(MeasureSpec.makeMeasureSpec(height * ratio.getX() / ratio.getY(),MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));}}@Overrideprotected Parcelable onSaveInstanceState() {SavedState state = new SavedState(super.onSaveInstanceState());state.facing = getFacing();state.ratio = getAspectRatio();state.autoFocus = getAutoFocus();state.flash = getFlash(); return state;}@Overrideprotected void onRestoreInstanceState(Parcelable state) {if (!(state instanceof SavedState)) {super.onRestoreInstanceState(state); return;}SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState());setFacing(ss.facing);setAspectRatio(ss.ratio);setAutoFocus(ss.autoFocus);setFlash(ss.flash);}/** * Open a camera device and start showing camera preview. This is typically called from * {@link Activity#onResume()}. */public void start() {if (!mImpl.start()) {//store the state ,and restore this state after fall back o Camera1Parcelable state=onSaveInstanceState();// Camera2 uses legacy hardware layer; fall back to Camera1mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()));onRestoreInstanceState(state);mImpl.start();}}/** * Stop camera preview and close the device. This is typically called from * {@link Activity#onPause()}. */public void stop() {mImpl.stop();}/** * @return {@code true} if the camera is opened. */public boolean isCameraOpened() {return mImpl.isCameraOpened();}/** * Add a new callback. * * @param callback The {@link Callback} to add. * @see #removeCallback(Callback) */public void addCallback(@NonNull Callback callback) {mCallbacks.add(callback);}/** * Remove a callback. * * @param callback The {@link Callback} to remove. * @see #addCallback(Callback) */public void removeCallback(@NonNull Callback callback) {mCallbacks.remove(callback);}/** * @param adjustViewBounds {@code true} if you want the CameraView to adjust its bounds to * preserve the aspect ratio of camera. * @see #getAdjustViewBounds() */public void setAdjustViewBounds(boolean adjustViewBounds) {if (mAdjustViewBounds != adjustViewBounds) {mAdjustViewBounds = adjustViewBounds;requestLayout();}}/** * @return True when this CameraView is adjusting its bounds to preserve the aspect ratio of * camera. * @see #setAdjustViewBounds(boolean) */public boolean getAdjustViewBounds() {return mAdjustViewBounds;}/** * Chooses camera by the direction it faces. * * @param facing The camera facing. Must be either {@link #FACING_BACK} or * {@link #FACING_FRONT}. */public void setFacing(@Facing int facing) {mImpl.setFacing(facing);}/** * Gets the direction that the current camera faces. * * @return The camera facing. */@Facingpublic int getFacing() {//noinspection WrongConstantreturn mImpl.getFacing();}/** * Gets all the aspect ratios supported by the current camera. */public Set getSupportedAspectRatios() {return mImpl.getSupportedAspectRatios();}/** * Sets the aspect ratio of camera. * * @param ratio The {@link AspectRatio} to be set. */public void setAspectRatio(@NonNull AspectRatio ratio) {if (mImpl.setAspectRatio(ratio)) {requestLayout();}}/** * Gets the current aspect ratio of camera. * * @return The current {@link AspectRatio}. Can be {@code null} if no camera is opened yet. */@Nullablepublic AspectRatio getAspectRatio() {return mImpl.getAspectRatio();}/** * Enables or disables the continuous auto-focus mode. When the current camera doesn't support * auto-focus, calling this method will be ignored. * * @param autoFocus {@code true} to enable continuous auto-focus mode. {@code false} to * disable it. */public void setAutoFocus(boolean autoFocus) {mImpl.setAutoFocus(autoFocus);}/** * Returns whether the continuous auto-focus mode is enabled. * * @return {@code true} if the continuous auto-focus mode is enabled. {@code false} if it is * disabled, or if it is not supported by the current camera. */public boolean getAutoFocus() {return mImpl.getAutoFocus();}/** * Sets the flash mode. * * @param flash The desired flash mode. */public void setFlash(@Flash int flash) {mImpl.setFlash(flash);}/** * Gets the current flash mode. * * @return The current flash mode. */@Flashpublic int getFlash() {//noinspection WrongConstantreturn mImpl.getFlash();}/** * Take a picture. The result will be returned to * {@link Callback#onPictureTaken(CameraView, byte[])}. */public void takePicture() {mImpl.takePicture();}private class CallbackBridge implements CameraViewImpl.Callback {private final ArrayList mCallbacks = new ArrayList<>(); private boolean mRequestLayoutOnOpen;CallbackBridge() {}public void add(Callback callback) {mCallbacks.add(callback);}public void remove(Callback callback) {mCallbacks.remove(callback);}@Overridepublic void onCameraOpened() {if (mRequestLayoutOnOpen) {mRequestLayoutOnOpen = false;requestLayout();}for (Callback callback : mCallbacks) {callback.onCameraOpened(CameraView.this);}}@Overridepublic void onCameraClosed() {for (Callback callback : mCallbacks) {callback.onCameraClosed(CameraView.this);}}@Overridepublic void onPictureTaken(byte[] data) {for (Callback callback : mCallbacks) {callback.onPictureTaken(CameraView.this, data);}}public void reserveRequestLayoutOnOpen() {mRequestLayoutOnOpen = true;}}protected static class SavedState extends BaseSavedState {@Facingint facing;AspectRatio ratio; boolean autoFocus;@Flashint flash;@SuppressWarnings("WrongConstant")public SavedState(Parcel source, ClassLoader loader) {super(source);facing = source.readInt();ratio = source.readParcelable(loader);autoFocus = source.readByte() != 0;flash = source.readInt();}public SavedState(Parcelable superState) {super(superState);}@Overridepublic void writeToParcel(Parcel out, int flags) {super.writeToParcel(out, flags);out.writeInt(facing);out.writeParcelable(ratio, 0);out.writeByte((byte) (autoFocus ? 1 : 0));out.writeInt(flash);}public static final Parcelable.Creator CREATOR= ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks() {@Overridepublic SavedState createFromParcel(Parcel in, ClassLoader loader) {return new SavedState(in, loader);}@Overridepublic SavedState[] newArray(int size) {return new SavedState[size];}});}/** * Callback for monitoring events about {@link CameraView}. */@SuppressWarnings("UnusedParameters")public abstract static class Callback {/** * Called when camera is opened. * * @param cameraView The associated {@link CameraView}. */public void onCameraOpened(CameraView cameraView) {}/** * Called when camera is closed. * * @param cameraView The associated {@link CameraView}. */public void onCameraClosed(CameraView cameraView) {}/** * Called when a picture is taken. * * @param cameraView The associated {@link CameraView}. * @param data JPEG data. */public void onPictureTaken(CameraView cameraView, byte[] data) {}}}

可以看出他继承了FrameLayout,在初始化的时候根据不同的api初始化不同的Camera对象达到了Camera和view的绑定

在activity中使用代码如下

/** 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.demo;import android.Manifest;import android.app.Dialog;import android.content.DialogInterface;import android.content.pm.PackageManager;import android.os.Build;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.HandlerThread;import android.support.annotation.NonNull;import android.support.annotation.StringRes;import android.support.design.widget.FloatingActionButton;import android.support.v4.app.ActivityCompat;import android.support.v4.app.DialogFragment;import android.support.v4.app.FragmentManager;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;import com.google.android.cameraview.AspectRatio;import com.google.android.cameraview.CameraView;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.util.Set;/*** This demo app saves the taken picture to a constant file.* $ adb pull /sdcard/Android/data/com.google.android.cameraview.demo/files/Pictures/picture.jpg*/public class MainActivity extends AppCompatActivity implementsActivityCompat.OnRequestPermissionsResultCallback,AspectRatioFragment.Listener {private static final String TAG = "MainActivity"; private static final int REQUEST_CAMERA_PERMISSION = 1; private static final String FRAGMENT_DIALOG = "dialog"; private static final int[] FLASH_OPTIONS = {CameraView.FLASH_AUTO,CameraView.FLASH_OFF,CameraView.FLASH_ON,}; private static final int[] FLASH_ICONS = {R.drawable.ic_flash_auto,R.drawable.ic_flash_off,R.drawable.ic_flash_on,}; private static final int[] FLASH_TITLES = {R.string.flash_auto,R.string.flash_off,R.string.flash_on,}; private int mCurrentFlash; private CameraView mCameraView; private Handler mBackgroundHandler; private View.OnClickListener mOnClickListener = new View.OnClickListener() {@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.take_picture:if (mCameraView != null) {mCameraView.takePicture();}break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mCameraView = (CameraView) findViewById(R.id.camera); if (mCameraView != null) {mCameraView.addCallback(mCallback);}FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.take_picture); if (fab != null) {fab.setOnClickListener(mOnClickListener);}Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);ActionBar actionBar = getSupportActionBar(); if (actionBar != null) {actionBar.setDisplayShowTitleEnabled(false);}}@Overrideprotected void onResume() {super.onResume(); if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED) {mCameraView.start();} else if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)) {ConfirmationDialogFragment.newInstance(R.string.camera_permission_confirmation, new String[]{Manifest.permission.CAMERA},REQUEST_CAMERA_PERMISSION,R.string.camera_permission_not_granted).show(getSupportFragmentManager(), FRAGMENT_DIALOG);} else {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},REQUEST_CAMERA_PERMISSION);}}@Overrideprotected void onPause() {mCameraView.stop(); super.onPause();}@Overrideprotected void onDestroy() {super.onDestroy(); if (mBackgroundHandler != null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {mBackgroundHandler.getLooper().quitSafely();} else {mBackgroundHandler.getLooper().quit();}mBackgroundHandler = null;}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults) {switch (requestCode) {case REQUEST_CAMERA_PERMISSION:if (permissions.length != 1 || grantResults.length != 1) {throw new RuntimeException("Error on requesting camera permission.");}if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, R.string.camera_permission_not_granted,Toast.LENGTH_SHORT).show();}// No need to start camera here; it is handled by onResumebreak;}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu); return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.aspect_ratio:FragmentManager fragmentManager = getSupportFragmentManager(); if (mCameraView != null&& fragmentManager.findFragmentByTag(FRAGMENT_DIALOG) == null) {final Set ratios = mCameraView.getSupportedAspectRatios(); final AspectRatio currentRatio = mCameraView.getAspectRatio();AspectRatioFragment.newInstance(ratios, currentRatio).show(fragmentManager, FRAGMENT_DIALOG);}return true; case R.id.switch_flash:if (mCameraView != null) {mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length;item.setTitle(FLASH_TITLES[mCurrentFlash]);item.setIcon(FLASH_ICONS[mCurrentFlash]);mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]);}return true; case R.id.switch_camera:if (mCameraView != null) {int facing = mCameraView.getFacing();mCameraView.setFacing(facing == CameraView.FACING_FRONT ?CameraView.FACING_BACK : CameraView.FACING_FRONT);}return true;}return super.onOptionsItemSelected(item);}@Overridepublic void onAspectRatioSelected(@NonNull AspectRatio ratio) {if (mCameraView != null) {Toast.makeText(this, ratio.toString(), Toast.LENGTH_SHORT).show();mCameraView.setAspectRatio(ratio);}}private Handler getBackgroundHandler() {if (mBackgroundHandler == null) {HandlerThread thread = new HandlerThread("background");thread.start();mBackgroundHandler = new Handler(thread.getLooper());}return mBackgroundHandler;}private CameraView.Callback mCallback= new CameraView.Callback() {@Overridepublic void onCameraOpened(CameraView cameraView) {Log.d(TAG, "onCameraOpened");}@Overridepublic void onCameraClosed(CameraView cameraView) {Log.d(TAG, "onCameraClosed");}@Overridepublic void onPictureTaken(CameraView cameraView, final byte[] data) {Log.d(TAG, "onPictureTaken " + data.length);Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT).show();getBackgroundHandler().post(new Runnable() {@Overridepublic void run() {File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES),"picture.jpg");OutputStream os = null; try {os = new FileOutputStream(file);os.write(data);os.close();} catch (IOException e) {Log.w(TAG, "Cannot write to " + file, e);} finally {if (os != null) {try {os.close();} catch (IOException e) {// Ignore}}}}});}}; public static class ConfirmationDialogFragment extends DialogFragment {private static final String ARG_MESSAGE = "message"; private static final String ARG_PERMISSIONS = "permissions"; private static final String ARG_REQUEST_CODE = "request_code"; private static final String ARG_NOT_GRANTED_MESSAGE = "not_granted_message"; public static ConfirmationDialogFragment newInstance(@StringRes int message,String[] permissions, int requestCode, @StringRes int notGrantedMessage) {ConfirmationDialogFragment fragment = new ConfirmationDialogFragment();Bundle args = new Bundle();args.putInt(ARG_MESSAGE, message);args.putStringArray(ARG_PERMISSIONS, permissions);args.putInt(ARG_REQUEST_CODE, requestCode);args.putInt(ARG_NOT_GRANTED_MESSAGE, notGrantedMessage);fragment.setArguments(args); return fragment;}@[email protected] Dialog onCreateDialog(Bundle savedInstanceState) {final Bundle args = getArguments(); return new AlertDialog.Builder(getActivity()).setMessage(args.getInt(ARG_MESSAGE)).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {String[] permissions = args.getStringArray(ARG_PERMISSIONS); if (permissions == null) {throw new IllegalArgumentException();}ActivityCompat.requestPermissions(getActivity(),permissions, args.getInt(ARG_REQUEST_CODE));}}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(getActivity(),args.getInt(ARG_NOT_GRANTED_MESSAGE),Toast.LENGTH_SHORT).show();}}).create();}}}

下面再来查看当前activity的layout布局

Advertisements

   

2022-05-09 21:35:28
0