android使用自定义相机避开部分小米手机app调用系统相机有水印会转向的问题

1.需求

我们要求很简单,就是拍照后显示效果要横屏拍的横着显示,竖屏拍着竖屏显示。但是我的手机小米5x等小米型号,存在横竖使用系统相机拍摄都是横屏显示的问题。更惨的是获取旋转角度什么的始终是0,没办法弃疗使用自定义相机,顺便可以去掉系统相机的水印。
简单归纳为以下一点:
横竖屏拍摄后,竖屏状态下查看图片始终是正的

2.选材

自己做个相机在我的项目中没有必要,我要的是普通相机,不用美颜高级功能,所以找个好的开源项目然后修改是我的目标。
目前只翻到两个github开源项目符合我的需求:
a.JCameraView
b.CameraKit

这两个都可以,相对来说JCameraView更细致一些,有一些动画,有对焦功能,所以选用了这个。

3.改造

1.去除顶部栏,把闪光灯功能放在右边

这是JCameraView内的项目图,实际上除了右上角的前置后置镜头切换,右上角还新增了一个闪光灯功能
这里写图片描述
但我思考了一下,右上角的镜头翻转在我的项目里不需要,直接invisible隐藏了,把闪光灯移动到了拍摄按钮右边,这样使用上更方便简洁一些。
修改了cameraApplication下的布局camera_view.xml
修改后如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#000000"
    android:orientation="vertical">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <VideoView
            android:id="@+id/video_preview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <ImageView
            android:id="@+id/image_photo"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#000"
            android:visibility="invisible"/>
    </FrameLayout>

    <!--必须有一个有高度的控件在上方,否则焦点框偏上方时会看不到-->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="10px"/>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/image_flash"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:visibility="invisible"
            android:src="@drawable/ic_flash_on"/>

        <ImageView
            android:id="@+id/image_switch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:visibility="invisible"
            android:src="@drawable/ic_camera"/>

    </LinearLayout>


    <com.cjt2325.cameralibrary.CaptureLayout
        android:id="@+id/capture_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:iconRight="@drawable/ic_flash_on"
        android:layout_gravity="bottom"/>

    <com.cjt2325.cameralibrary.FoucsView
        android:id="@+id/fouce_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="invisible"
        />
</FrameLayout>

JCameraView类里面不显示右上角控件,把两句visible隐藏掉,这个不写了,很容易找;JCameraView类右侧按钮点击需改为:

mCaptureLayout.setRightClickListener(new ClickListener() {
            @Override
            public void onClick() {
//                if (rightClickListener != null) {
//                    rightClickListener.onClick();
//                }
                mFlashLamp.performClick();
                setRightFlashRes();
            }
        });
private void setRightFlashRes() {
        switch (type_flash) {
            case TYPE_FLASH_AUTO:
                mCaptureLayout.setRightResource(R.drawable.ic_flash_auto);
                machine.flash(Camera.Parameters.FLASH_MODE_AUTO);
                break;
            case TYPE_FLASH_ON:
                mCaptureLayout.setRightResource(R.drawable.ic_flash_on);
                machine.flash(Camera.Parameters.FLASH_MODE_ON);
                break;
            case TYPE_FLASH_OFF:
                mCaptureLayout.setRightResource(R.drawable.ic_flash_off);
                machine.flash(Camera.Parameters.FLASH_MODE_OFF);
                break;
        }
    }

2.去掉录像功能

此相机长按具有录像功能,需对jcamera进行设置:
修改CameraActivity:

jCameraView.setFeatures(JCameraView.BUTTON_STATE_ONLY_CAPTURE);//设置为只能拍照

3.去掉录音权限请求

不用录视频也就用不到录音,需修改MainActivity:

/**
     * 获取权限
     */
    private void getPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager
                    .PERMISSION_GRANTED &&
//                    ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager
//                            .PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager
                            .PERMISSION_GRANTED) {
                startActivityForResult(new Intent(MainActivity.this, CameraActivity.class), 100);
            } else {
                //不具有获取权限,需要进行权限申请
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
//                        Manifest.permission.RECORD_AUDIO,
                        Manifest.permission.CAMERA}, GET_PERMISSION_REQUEST);
            }
        } else {
            startActivityForResult(new Intent(MainActivity.this, CameraActivity.class), 100);
        }
    }
@TargetApi(23)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == GET_PERMISSION_REQUEST) {
            int size = 0;
            if (grantResults.length >= 1) {
                int writeResult = grantResults[0];
                //读写内存权限
                boolean writeGranted = writeResult == PackageManager.PERMISSION_GRANTED;//读写内存权限
                if (!writeGranted) {
                    size++;
                }
                //相机权限
                int cameraPermissionResult = grantResults[1];
                boolean cameraPermissionGranted = cameraPermissionResult == PackageManager.PERMISSION_GRANTED;
                if (!cameraPermissionGranted) {
                    size++;
                }
                if (size == 0) {
                    startActivityForResult(new Intent(MainActivity.this, CameraActivity.class), 100);
                } else {
                    Toast.makeText(this, "请到设置-权限管理中开启", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

4.自动对焦

这里提一点,因为VideoView这个控件有点奇葩,或者说手机厂商原因,此控件上方下方必须都有遮盖物(要有宽高),不然中间放置的对焦框就可能会在某些位置时不可见。
以下全部为修改JCameraView.java
首先,此对焦框需要对焦可见:

//对焦框指示器动画
    private void setFocusViewWidthAnimation(float x, float y) {
        if(mPhoto.getVisibility() != View.VISIBLE)
            mFoucsView.setVisibility(View.VISIBLE);
        machine.foucs(x, y, new CameraInterface.FocusCallback() {
            @Override
            public void focusSuccess() {
                mFoucsView.setVisibility(INVISIBLE);
            }
        });
    }
@Override
    public void showPicture(Bitmap bitmap, boolean isVertical) {
        if (isVertical) {
            mPhoto.setScaleType(ImageView.ScaleType.FIT_XY);
        } else {
            mPhoto.setScaleType(ImageView.ScaleType.FIT_CENTER);
        }
        captureBitmap = bitmap;
        mPhoto.setImageBitmap(bitmap);
        mPhoto.setVisibility(VISIBLE);
        mFoucsView.setVisibility(INVISIBLE);
        mCaptureLayout.startAlphaAnimation();
        mCaptureLayout.startTypeBtnAnimator();
    }
@Override
    public boolean handlerFoucs(float x, float y) {
        if (y > mCaptureLayout.getTop()) {
            return false;
        }
        if (x < mFoucsView.getWidth() / 2) {
            x = mFoucsView.getWidth() / 2;
        }
        if (x > layout_width - mFoucsView.getWidth() / 2) {
            x = layout_width - mFoucsView.getWidth() / 2;
        }
        if (y < mFoucsView.getWidth() / 2) {
            y = mFoucsView.getWidth() / 2;
        }
        if (y > mCaptureLayout.getTop() - mFoucsView.getWidth() / 2) {
            y = mCaptureLayout.getTop() - mFoucsView.getWidth() / 2;
        }
        if(mPhoto.getVisibility() != View.VISIBLE)
        mFoucsView.setVisibility(View.VISIBLE);
        mFoucsView.setX(x - mFoucsView.getWidth() / 2);
        mFoucsView.setY(y - mFoucsView.getHeight() / 2);
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(mFoucsView, "scaleX", 1, 0.6f);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(mFoucsView, "scaleY", 1, 0.6f);
        ObjectAnimator alpha = ObjectAnimator.ofFloat(mFoucsView, "alpha", 1f, 0.4f, 1f, 0.4f, 1f, 0.4f, 1f);
        AnimatorSet animSet = new AnimatorSet();
        animSet.play(scaleX).with(scaleY).before(alpha);
        animSet.setDuration(400);
        animSet.start();
        return true;
    }

这里判断了mPhotoView,mPhotoView是拍摄完成后用来显示拍摄结果的,当显示拍摄结果的时候,按道理说应该不可见对焦框,所以关掉。

然后我们使用Handler来进行定时对焦,这里我取的是5秒:

public void onResume() {
        LogUtil.i("JCameraView onResume");
        resetState(TYPE_DEFAULT); //重置状态
        CameraInterface.getInstance().registerSensorManager(mContext);
        CameraInterface.getInstance().setSwitchView(mSwitchCamera, mFlashLamp);
        machine.start(mVideoView.getHolder(), screenProp);
        if(handler == null){
            handler = new MyHandler(this);
        }
        handler.sendEmptyMessage(1);
    }

    private MyHandler handler;

    //生命周期onPause
    public void onPause() {
        LogUtil.i("JCameraView onPause");
        stopVideo();
        resetState(TYPE_PICTURE);
        CameraInterface.getInstance().isPreview(false);
        CameraInterface.getInstance().unregisterSensorManager(mContext);
        if(handler!=null)
            handler.removeCallbacksAndMessages(null);
    }

初始化时,取屏幕中心为聚焦x,y,之后取点击点:

 focusx =getScreenWidth()/2.0f;
        focusy = getScreenHeight()/2.0f;
private float getScreenHeight(){
        WindowManager manager = ((Activity)getContext()).getWindowManager();
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }

    private float getScreenWidth(){
        WindowManager manager = ((Activity)getContext()).getWindowManager();
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

onTouchEvent->ACTION_DOWN添加:

 focusx = event.getX();
 focusy = event.getY();

handler:

 public static class MyHandler extends Handler{
        private WeakReference<JCameraView> wview;
        public MyHandler(JCameraView view){
            wview = new WeakReference<JCameraView>(view);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(wview == null || wview.get() == null){
                removeCallbacksAndMessages(this);
                return;
            }

            JCameraView view = wview.get();
            view.setFocusViewWidthAnimation(view.focusx,view.focusy);
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    sendEmptyMessage(1);
                }
            },5000);
        }
    }

这里我定的是5秒,你可以根据自己的需求修改为合适的时间

猜你喜欢

转载自blog.csdn.net/yu_duan_hun/article/details/80403823