【问题标题】:Android focus camera on long press of shut button长按关闭按钮上的Android对焦相机
【发布时间】:2017-02-05 22:09:47
【问题描述】:

请帮忙。有没有办法使用相机 API(Android SDK 19 和 17 之间的版本)让相机在长按关闭按钮拍照前对焦?

换句话说,我长按相机按钮(我的意思是它可能是相机按钮或屏幕上的按钮)焦点必须开始,并且在第一秒我释放该按钮它应该拍照.

请帮忙。

【问题讨论】:

    标签: android android-camera android-camera2


    【解决方案1】:

    好的,因此对于此功能,有两个重要的方法 onTouchEvent(我可以在其中检测释放按钮)和 setOnLongClickListener(检测拍摄照片的长按按钮)。在下面的代码中,我创建了一个自定义视图(名为 DrawCameraOptions 类),它在 SurfaceView 上方的屏幕上绘制一个红色圆圈,另一个自定义视图(名为 DrawingRectForFocalisationAreaView 类)在焦点区域的 SurfaceView 上绘制一个矩形。

    fragment_take_picture.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
    
        <SurfaceView
            android:id="@+id/surfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <customs.cameras.DrawingRectForFocalisationAreaView
            android:id="@+id/drawingFocusRectangle_FragmentTakePicture"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    
        <customs.cameras.DrawCameraOptions
            android:id="@+id/takePicture_FragmentTakePicture2"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="@android:color/transparent"
            android:layout_alignParentBottom="true"/>
    
    </RelativeLayout>
    

    UpdateDrawingFocusAreaRect 接口

    package network.callbacks;
    
    import android.graphics.Rect;
    import android.hardware.Camera;
    
    /**
     * Created by EmiG on 02.02.2017.
     */
    
    public interface UpdateDrawingFocusAreaRect {
    
        public void repaintRectFocusArea(final Rect touchRect);
    
        public void takePictureOnLongPress();
    }
    

    DrawCameraOptions 类

    package customs.cameras;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    import network.callbacks.UpdateDrawingFocusAreaRect;
    
    /**
     * Created by EmiG on 18.01.2017.
     */
    
    public class DrawCameraOptions extends View {
    
        private Paint paint;
        private UpdateDrawingFocusAreaRect callback;
        private static final String TAG="TakePictureFragment2";
    
        public DrawCameraOptions(Context context) {
            super(context);
    
            this.initComponets();
        }
    
        public void setCallback(UpdateDrawingFocusAreaRect callback) {
            this.callback = callback;
        }
    
        public DrawCameraOptions(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            this.initComponets();
        }
    
        public DrawCameraOptions(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            this.initComponets();
        }
    
        private void initComponets()
        {
            this.paint=new Paint(paint.ANTI_ALIAS_FLAG);
            this.paint.setStyle(Paint.Style.FILL_AND_STROKE);
            this.paint.setColor(Color.RED);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            //super.onDraw(canvas);
    
            final int width=getWidth() - getPaddingLeft() - getPaddingRight();//of the view
            final int height=getHeight() - getPaddingTop() - getPaddingBottom();
            final int cx=width/2 + getPaddingLeft();
            final int cy=height/2 + getPaddingTop();
            final float diameter= Math.min(width, height) - paint.getStrokeWidth();
            final float radious=diameter/2;
            canvas.drawCircle(cx,cy,radious,this.paint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    Log.i(TAG,"ACTION_UP");
                    if(null!=this.callback)
                    {
                        this.callback.takePictureOnLongPress();
                    }
                    break;
            }
            return super.onTouchEvent(event);
        }
    }
    

    DrawingRectForFocalisationAreaView 类

    package customs.cameras;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.View;
    
    /**
     * Created by EmiG on 25.01.2017.
     */
    
    public class DrawingRectForFocalisationAreaView extends View {
    
        private Paint drawingPaint;
    
        boolean haveTouch;
        private Rect touchArea;
        private static final int RECT_DIMENSIONS=50;
    
        public DrawingRectForFocalisationAreaView(Context context) {
            super(context);
    
            this.init();
        }
    
        public DrawingRectForFocalisationAreaView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            this.init();
        }
    
        public DrawingRectForFocalisationAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            this.init();
        }
    
        private void init()
        {
            this.drawingPaint = new Paint();
            this.drawingPaint.setColor(Color.RED);
            this.drawingPaint.setStyle(Paint.Style.STROKE);
            this.drawingPaint.setStrokeWidth(2);
            this.haveTouch = false;
        }
    
        public void setHaveTouch(boolean t, Rect tArea){
            this.drawingPaint.setColor(Color.RED);
            this.haveTouch = t;
            this.touchArea = tArea;
        }
    
        public void validateFocus()
        {
            if(Color.RED == this.drawingPaint.getColor())
            {
                this.drawingPaint.setColor(Color.GREEN);
                this.haveTouch=true;
                invalidate();
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
    
            if(this.haveTouch && null!=canvas&& null!=this.drawingPaint){
    
                canvas.drawRect(this.touchArea.left-RECT_DIMENSIONS, this.touchArea.top-RECT_DIMENSIONS, this.touchArea.right+RECT_DIMENSIONS, this.touchArea.bottom+RECT_DIMENSIONS, this.drawingPaint);
                this.haveTouch=false;
            }
        }
    }
    

    TakePictureFragment2 类

    public class TakePictureFragment2 extends Fragment implements SurfaceHolder.Callback, View.OnTouchListener, UpdateDrawingFocusAreaRect {
    
        private static final String TAG = TakePictureFragment2.class.getSimpleName();
    
        //region Focus variabiles
        private boolean bIsPictureTaking, bIsAutoFocusStarted, bIsAutoFocused, USE_AUTOFOCUS, isFocusated, isLongPressed, canTakePicture;
        private static final int FOCUS_AREA_SIZE = 300;
        //endregion
    
        private boolean camCondition = false;  // conditional variable for camera preview checking and set to false
    
        //region Camera object
        private Camera camera;
        private SurfaceView surfaceView;
        private SurfaceHolder surfaceHolder;
    
        private Camera.PictureCallback jpegCallback;
        //endregion
    
        //region Execute multiple calculation functionality for drawing
        private ThreadPoolExecutor threadPoolExecutor;
        public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
        //endregion
    
        //region Custom Objects that draw on the screen
        private DrawCameraOptions takePictureButton;// Draw shuttbutton for capture image
        //Desenare pe  ecran punct de focalizare
        private DrawingRectForFocalisationAreaView drawingRectangleOnScreen;//Draw blue rectangle on focus area
        //endregion
    
        //region Fragent methods
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            Log.i(TAG, "onCreateView()");
            View view = inflater.inflate(R.layout.fragment_take_picture, container, false);
            if (null != view) {
                return view;
            }
    
            return super.onCreateView(inflater, container, savedInstanceState);
        }
    
        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            Log.i(TAG, "onActivityCreated()");
    
    
            this.initOnTouchListener();
        }
    
        @Override
        public void onResume() {
            super.onResume();
            Log.i(TAG, "onResume()");
    
            this.initComponents();
    
            if (null != camera) {
                try {
                    camera.setPreviewDisplay(surfaceHolder); // setting preview of camera
                    camera.startPreview();
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
            }
        }
        //endregion
    
    
    
    
    //region Initial Components
        private void initOnTouchListener() {
            if (null != this.getView()) {
                this.getView().setOnTouchListener(TakePictureFragment2.this);
            }
        }
    
        private void initComponents() {
            if (null != getView()) {
    
                this.drawingRectangleOnScreen = (DrawingRectForFocalisationAreaView) getView().findViewById(R.id.drawingFocusRectangle_FragmentTakePicture);
    
                takePictureButton = (DrawCameraOptions) getView().findViewById(R.id.takePicture_FragmentTakePicture2);
                takePictureButton.setCallback(TakePictureFragment2.this);
    
    
                takePictureButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Log.i(TAG,"Simple click");
    
                        camera.takePicture(null, null, jpegCallback);
                    }
                });
    
                takePictureButton.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View v) {
                        Log.i(TAG,"Long click");
                        final Context context=getView().getContext();
                        isLongPressed=true;
                        synchronized (this) {
                            if (camera != null) {
                                camera.cancelAutoFocus();
                                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
                                    if (!bIsPictureTaking && !bIsAutoFocusStarted) {
                                        bIsAutoFocusStarted = true;
                                        new AsyncTask<Void, Void, Void>() {
                                            @Override
                                            protected Void doInBackground(Void... params) {
                                                try {
                                                    Camera.Parameters parameters = camera.getParameters();
                                                    if (parameters.getMaxNumMeteringAreas() > 0) {
                                                        Log.i(TAG, "fancy !");
                                                        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
                                                        Point screenDsiplay=new Point();
                                                        display.getSize(screenDsiplay);
                                                        Rect rect = calculateFocusArea(screenDsiplay.x/2, screenDsiplay.y/2);
                                                        display=null;
                                                        screenDsiplay=null;
                                                        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                                                        List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
                                                        meteringAreas.add(new Camera.Area(rect, 1000));
                                                        parameters.setFocusAreas(meteringAreas);
    
                                                        camera.setParameters(parameters);
                                                        camera.autoFocus(mAutoFocusTakePictureCallback);
                                                    } else {
                                                        camera.autoFocus(mAutoFocusTakePictureCallback);
                                                    }
                                                    bIsAutoFocusStarted = false;
                                                } catch (Exception e) {
                                                    Log.e(TAG, "Error " + e.getMessage());
                                                    e.printStackTrace();
                                                }
                                                System.gc();
                                                return null;
                                            }
                                        }.execute((Void[]) null);
                                    }
                                } else {
                                    if (!bIsPictureTaking && !bIsAutoFocusStarted) {
                                        bIsAutoFocusStarted = true;
                                        new AsyncTask<Void, Void, Void>() {
                                            @Override
                                            protected Void doInBackground(Void... params) {
                                                try {
                                                    Camera.Parameters parameters = camera.getParameters();
                                                    if (parameters.getMaxNumMeteringAreas() > 0) {
                                                        Log.i(TAG, "fancy !");
                                                        Display display2 = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
                                                        Point screenDsiplay2=new Point();
                                                        display2.getSize(screenDsiplay2);
                                                        Rect rect = calculateFocusArea(screenDsiplay2.x/2, screenDsiplay2.y/2);
                                                        display2=null;
                                                        screenDsiplay2=null;
    
                                                        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                                                        List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
                                                        meteringAreas.add(new Camera.Area(rect, 1000));
                                                        parameters.setFocusAreas(meteringAreas);
    
                                                        camera.setParameters(parameters);
                                                        camera.autoFocus(mAutoFocusTakePictureCallback);
                                                    } else {
                                                        camera.autoFocus(mAutoFocusTakePictureCallback);
                                                    }
                                                    bIsAutoFocusStarted = false;
    
                                                } catch (Exception e) {
                                                    Log.e(TAG, "Error " + e.getMessage());
                                                    e.printStackTrace();
                                                }
    
                                                System.gc();
                                                return null;
                                            }
                                        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
                                    }
                                }
                            }
                        }
    
                        return true;
                    }
                });
    
    
                surfaceView = (SurfaceView) getView().findViewById(R.id.surfaceView);
                surfaceHolder = surfaceView.getHolder();
                // deprecated setting, but required on Android versions prior to 3.0
                surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
                // Install a SurfaceHolder.Callback so we get notified when the
                // underlying surface is created and destroyed.
                surfaceHolder.addCallback(this);
    
    
                jpegCallback = new Camera.PictureCallback() {
                    public void onPictureTaken(final byte[] data, Camera camera) {
                        USE_AUTOFOCUS=false;
                        canTakePicture=false;
                        final Context context = getView().getContext();
                        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
                            new AsyncTask<Void, Void, Void>() {
                                @Override
                                protected Void doInBackground(Void... params) {
                                    bIsPictureTaking = true;  //set it to true to avoid onKeyDown dispatching during taking picture. it may be time-consuming
                                    bIsAutoFocused = false; //reset to false
                                    bIsAutoFocusStarted = false; //reset to false
    
                                    FileOutputStream outStream = null;
                                    try {
                                        final GregorianCalendar gregorianCalendar = new GregorianCalendar();
                                        gregorianCalendar.setTime(new Date());
                                        final StringBuffer stringBufferFileName = new StringBuffer();
                                        stringBufferFileName.append(gregorianCalendar.get(Calendar.YEAR));
                                        stringBufferFileName.append("_");
                                        stringBufferFileName.append(gregorianCalendar.get(Calendar.MONTH) + 1);
                                        stringBufferFileName.append("_");
                                        stringBufferFileName.append(gregorianCalendar.get(Calendar.DAY_OF_MONTH) + 1);
    
                                        final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "Rompetrol", stringBufferFileName.toString());
                                        if (!root.exists()) {
                                            root.mkdirs();
                                        }
                                        final File gpxfile = new File(root, System.currentTimeMillis() + ".jpg");
    
    
                                        outStream = new FileOutputStream(gpxfile);
                                        outStream.write(data);
                                        outStream.close();
                                        Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
    
                                        final AudioManager meng = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
                                        int volume = meng.getStreamVolume(AudioManager.STREAM_NOTIFICATION);
    
                                        if (volume != 0) {
                                            final MediaPlayer _shootMP = MediaPlayer.create(context, Uri.parse("file:///system/media/audio/ui/camera_click.ogg"));
                                            _shootMP.start();
                                        }
    
                                        bIsPictureTaking = false;
                                        JSONObject jsonObjecte = new JSONObject();
                                        try {
                                            jsonObjecte.put(EventBusMessages.OPERATION_TO_PERFORM.getkey(), EventBusMessages.CHANGE_FRAGMENT.getkey());
                                            jsonObjecte.put(EventBusMessages.CHANGE_FRAGMENT.getkey(), FragmentList.DISPLAY_PICTURE_FRAGMENT.getKey());
                                            jsonObjecte.put(EventBusMessages.PICTURE_PATH.getkey(), gpxfile.getAbsolutePath());
    
                                            EventBus.getDefault().post(jsonObjecte);
                                        } catch (JSONException e) {
                                            e.printStackTrace();
                                        }
    
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
    
                                    return null;
                                }
                            }.execute((Void[]) null);
                        }
                        else
                        {
                            new AsyncTask<Void, Void, Void>() {
                                @Override
                                protected Void doInBackground(Void... params) {
                                    bIsPictureTaking = true;  //set it to true to avoid onKeyDown dispatching during taking picture. it may be time-consuming
                                    bIsAutoFocused = false; //reset to false
                                    bIsAutoFocusStarted = false; //reset to false
    
                                    FileOutputStream outStream = null;
                                    try {
                                        final GregorianCalendar gregorianCalendar = new GregorianCalendar();
                                        gregorianCalendar.setTime(new Date());
                                        final StringBuffer stringBufferFileName = new StringBuffer();
                                        stringBufferFileName.append(gregorianCalendar.get(Calendar.YEAR));
                                        stringBufferFileName.append("_");
                                        stringBufferFileName.append(gregorianCalendar.get(Calendar.MONTH) + 1);
                                        stringBufferFileName.append("_");
                                        stringBufferFileName.append(gregorianCalendar.get(Calendar.DAY_OF_MONTH) + 1);
    
                                        final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "Rompetrol", stringBufferFileName.toString());
                                        if (!root.exists()) {
                                            root.mkdirs();
                                        }
                                        final File gpxfile = new File(root, System.currentTimeMillis() + ".jpg");
    
    
                                        outStream = new FileOutputStream(gpxfile);
                                        outStream.write(data);
                                        outStream.close();
                                        Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
    
                                        final AudioManager meng = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
                                        int volume = meng.getStreamVolume(AudioManager.STREAM_NOTIFICATION);
    
                                        if (volume != 0) {
                                            final MediaPlayer _shootMP = MediaPlayer.create(context, Uri.parse("file:///system/media/audio/ui/camera_click.ogg"));
                                            _shootMP.start();
                                        }
    
                                        bIsPictureTaking = false;
                                        JSONObject jsonObjecte = new JSONObject();
                                        try {
                                            jsonObjecte.put(EventBusMessages.OPERATION_TO_PERFORM.getkey(), EventBusMessages.CHANGE_FRAGMENT.getkey());
                                            jsonObjecte.put(EventBusMessages.CHANGE_FRAGMENT.getkey(), FragmentList.DISPLAY_PICTURE_FRAGMENT.getKey());
                                            jsonObjecte.put(EventBusMessages.PICTURE_PATH.getkey(), gpxfile.getAbsolutePath());
    
                                            EventBus.getDefault().post(jsonObjecte);
                                        } catch (JSONException e) {
                                            e.printStackTrace();
                                        }
    
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
    
                                    return null;
                                }
                            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,(Void[]) null);
                        }
    
                        // stop preview before making changes
                        try {
                            camera.stopPreview();
                            surfaceView.invalidate();
                            surfaceHolder = null;
                        } catch (Exception e) {
                            // ignore: tried to stop a non-existent preview
                        }
                    }
                };
    
    
                this.threadPoolExecutor = new ThreadPoolExecutor(
                        NUMBER_OF_CORES * 2,
                        NUMBER_OF_CORES * 2,
                        20L,
                        TimeUnit.SECONDS,
                        new LinkedBlockingQueue<Runnable>());
    
                this.USE_AUTOFOCUS = false;
                this.bIsPictureTaking = false;  //set it to true to avoid onKeyDown dispatching during taking picture. it may be time-consuming
                this.bIsAutoFocused = false; //reset to false
                this.bIsAutoFocusStarted = false; //reset to false
                this.isLongPressed=false;//reset to false
                this.canTakePicture=false;//reset to false
            }
        }
        //endregion
    
    
    public void repaintRectFocusArea(final Rect touchRect) {
        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
            drawingRectangleOnScreen.setHaveTouch(true, touchRect);
            drawingRectangleOnScreen.invalidate();
        } else {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    drawingRectangleOnScreen.setHaveTouch(true, touchRect);
                    drawingRectangleOnScreen.invalidate();
                }
            });
        }
    }
    
    
    public void takePictureOnLongPress() {
        if(this.isLongPressed)
        {
            Log.i(TAG,"ACTION_BUTTON_RELEASE");
            this.isLongPressed=false;
            this.canTakePicture=true;
            camera.takePicture(null, null, jpegCallback);
        }
    }
    

    请原谅我写的不好的代码。

    【讨论】:

    • 对于 TakePictureFragment2 类,stackoverflow 似乎不允许我编写所有的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-02
    • 1970-01-01
    相关资源
    最近更新 更多