package com.afollestad.materialcamera.internal; import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Point; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.Toast; import com.afollestad.materialcamera.CaptureActivity; import com.afollestad.materialcamera.ICallback; import com.afollestad.materialcamera.R; import com.afollestad.materialcamera.util.CameraUtil; import com.afollestad.materialcamera.util.Degrees; import com.afollestad.materialcamera.util.ImageUtil; import com.afollestad.materialcamera.util.ManufacturerUtil; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import static com.afollestad.materialcamera.internal.BaseCaptureActivity.CAMERA_POSITION_BACK; import static com.afollestad.materialcamera.internal.BaseCaptureActivity.CAMERA_POSITION_FRONT; import static com.afollestad.materialcamera.internal.BaseCaptureActivity.CAMERA_POSITION_UNKNOWN; import static com.afollestad.materialcamera.internal.BaseCaptureActivity.FLASH_MODE_ALWAYS_ON; import static com.afollestad.materialcamera.internal.BaseCaptureActivity.FLASH_MODE_AUTO; import static com.afollestad.materialcamera.internal.BaseCaptureActivity.FLASH_MODE_OFF; /** * @author Aidan Follestad (afollestad) */ @SuppressWarnings("deprecation") @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class CameraFragment extends BaseCameraFragment implements View.OnClickListener { CameraPreview mPreviewView; RelativeLayout mPreviewFrame; private AutoFitTextureView autoFitTextureView; private Camera.Size mVideoSize; private Camera mCamera; private Point mWindowSize; private int mDisplayOrientation; private boolean mIsAutoFocusing; List<Integer> mFlashModes; private LinearLayout body; private boolean mReachedZero; private boolean canShowPreView=false; private int videoWidth=640; private int videoHeight=480; public static CameraFragment newInstance() { CameraFragment fragment = new CameraFragment(); fragment.setRetainInstance(true); return fragment; } private static Camera.Size chooseVideoSize(BaseCaptureInterface ci, List<Camera.Size> choices) { Camera.Size backupSize = null; for (Camera.Size size : choices) { if (size.height <= ci.videoPreferredHeight()) { if (size.width == size.height * ci.videoPreferredAspect()) return size; if (ci.videoPreferredHeight() >= size.height) backupSize = size; } } if (backupSize != null) return backupSize; LOG(CameraFragment.class, "Couldn't find any suitable video size"); return choices.get(choices.size() - 1); } private static Camera.Size chooseOptimalSize(List<Camera.Size> choices, int width, int height, Camera.Size aspectRatio) { // Collect the supported resolutions that are at least as big as the preview Surface List<Camera.Size> bigEnough = new ArrayList<>(); int w = aspectRatio.width; int h = aspectRatio.height; for (Camera.Size option : choices) { if (option.height == width * h / w && option.width >= width && option.height >= height) { bigEnough.add(option); } } // Pick the smallest of those, assuming we found any if (bigEnough.size() > 0) { return Collections.min(bigEnough, new CompareSizesByArea()); } else { LOG(CameraFragment.class, "Couldn't find any suitable preview size"); return aspectRatio; } } @Override public void onViewCreated(final View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mPreviewFrame = (RelativeLayout) view.findViewById(R.id.rootFrame); body= (LinearLayout) view.findViewById(R.id.body); autoFitTextureView= (AutoFitTextureView) view.findViewById(R.id.texture); autoFitTextureView.setVisibility(View.GONE); mPreviewFrame.setOnClickListener(this); } private void showPopupWindow() { CaptureActivity activity= (CaptureActivity) getActivity(); activity.setCanShowGuide(false); View view= LayoutInflater.from(getActivity()).inflate(R.layout.guide_record,null); final PopupWindow popupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, true); popupWindow.setTouchable(true); popupWindow.setTouchInterceptor(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return false; // 这里如果返回true的话,touch事件将被拦截 // 拦截后 PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss } }); // 如果不设置PopupWindow的背景,无论是点击外部区域还是Back键都无法dismiss弹框 // 我觉得这里是API的一个bug popupWindow.setBackgroundDrawable(getResources().getDrawable( R.drawable.back_guide)); // 设置好参数之后再show int[] location = new int[2]; mButtonVideo.getLocationOnScreen(location); view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); int popupWidth = view.getMeasuredWidth(); int popupHeight = view.getMeasuredHeight(); popupWindow.showAtLocation(mButtonVideo, Gravity.NO_GRAVITY, (location[0]+mButtonVideo.getWidth()/2)-popupWidth/2, location[1]-popupHeight-20); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (popupWindow.isShowing()){ popupWindow.dismiss(); } } }); } @Override public void onDestroyView() { super.onDestroyView(); try { mPreviewView.getHolder().getSurface().release(); } catch (Throwable ignored) { } mPreviewFrame = null; } @Override public void onResume() { super.onResume(); openCamera(); } @Override public void onPause() { if (mCamera != null) mCamera.lock(); super.onPause(); } @Override public void onClick(View view) { if (view.getId() == R.id.rootFrame) { if (mCamera == null || mIsAutoFocusing) return; try { mIsAutoFocusing = true; mCamera.cancelAutoFocus(); Camera.Parameters parameters=mCamera.getParameters(); List<String> list=parameters.getSupportedFocusModes(); mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { mIsAutoFocusing = false; if (!success) Toast.makeText(getActivity(), "Unable to auto-focus!", Toast.LENGTH_SHORT).show(); } }); } catch (Throwable t) { t.printStackTrace(); } } else { super.onClick(view); } } @Override public void openCamera() { final Activity activity = getActivity(); if (null == activity || activity.isFinishing()) return; try { final int mBackCameraId = mInterface.getBackCamera() != null ? (Integer) mInterface.getBackCamera() : -1; final int mFrontCameraId = mInterface.getFrontCamera() != null ? (Integer) mInterface.getFrontCamera() : -1; if (mBackCameraId == -1 || mFrontCameraId == -1) { int numberOfCameras = Camera.getNumberOfCameras(); if (numberOfCameras == 0) { throwError(new Exception("No cameras are available on this device.")); return; } for (int i = 0; i < numberOfCameras; i++) { //noinspection ConstantConditions if (mFrontCameraId != -1 && mBackCameraId != -1) break; Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && mFrontCameraId == -1) { mInterface.setFrontCamera(i); } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK && mBackCameraId == -1) { mInterface.setBackCamera(i); } } } switch (getCurrentCameraPosition()) { case CAMERA_POSITION_FRONT: setImageRes(mButtonFacing, mInterface.iconRearCamera()); break; case CAMERA_POSITION_BACK: setImageRes(mButtonFacing, mInterface.iconFrontCamera()); break; case CAMERA_POSITION_UNKNOWN: default: if (!getArguments().getBoolean(CameraIntentKey.DEFAULT_TO_FRONT_FACING, false)) { // Check front facing first if (mInterface.getFrontCamera() != null && (Integer) mInterface.getFrontCamera() != -1) { setImageRes(mButtonFacing, mInterface.iconRearCamera()); mInterface.setCameraPosition(CAMERA_POSITION_FRONT); } else { setImageRes(mButtonFacing, mInterface.iconFrontCamera()); if (mInterface.getBackCamera() != null && (Integer) mInterface.getBackCamera() != -1) mInterface.setCameraPosition(CAMERA_POSITION_BACK); else mInterface.setCameraPosition(CAMERA_POSITION_UNKNOWN); } } else { // Check back facing first if (mInterface.getBackCamera() != null && (Integer) mInterface.getBackCamera() != -1) { setImageRes(mButtonFacing, mInterface.iconFrontCamera()); mInterface.setCameraPosition(CAMERA_POSITION_BACK); } else { setImageRes(mButtonFacing, mInterface.iconRearCamera()); if (mInterface.getFrontCamera() != null && (Integer) mInterface.getFrontCamera() != -1) mInterface.setCameraPosition(CAMERA_POSITION_FRONT); else mInterface.setCameraPosition(CAMERA_POSITION_UNKNOWN); } } break; } if (mWindowSize == null) mWindowSize = new Point(); activity.getWindowManager().getDefaultDisplay().getSize(mWindowSize); final int toOpen = getCurrentCameraId(); mCamera = Camera.open(toOpen == -1 ? 0 : toOpen); Camera.Parameters parameters = mCamera.getParameters(); List<Camera.Size> videoSizes = parameters.getSupportedVideoSizes(); if (videoSizes == null || videoSizes.size() == 0) videoSizes = parameters.getSupportedPreviewSizes(); mVideoSize = chooseVideoSize((BaseCaptureActivity) activity, videoSizes); Camera.Size previewSize = chooseOptimalSize(parameters.getSupportedPreviewSizes(), mWindowSize.x, mWindowSize.y, mVideoSize); if (ManufacturerUtil.isSamsungGalaxyS3()) { parameters.setPreviewSize(ManufacturerUtil.SAMSUNG_S3_PREVIEW_WIDTH, ManufacturerUtil.SAMSUNG_S3_PREVIEW_HEIGHT); } else { parameters.setPreviewSize(videoWidth, 480); Log.e("lzf_parameters", "line234 " + previewSize.width + " " + previewSize.height); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) parameters.setRecordingHint(true); } List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes(); int length = pictureSizes.size(); for (int i = 0; i < length; i++) { Log.e("TAG","SupportedPictureSizes : " + pictureSizes.get(i).width + "x" + pictureSizes.get(i).height); } Camera.Size mStillShotSize = getHighestSupportedStillShotSize(parameters.getSupportedPictureSizes()); Log.e("lzf_parameters", "line240 " + mStillShotSize.width + " " + mStillShotSize.height); Log.e("lzf_pictureSize",previewSize.width+" "+ previewSize.height); parameters.setPictureSize(videoWidth, videoHeight); setCameraDisplayOrientation(parameters); mCamera.setParameters(parameters); mFlashModes = CameraUtil.getSupportedFlashModes(this.getActivity(), parameters); mInterface.setFlashModes(mFlashModes); onFlashModesLoaded(); createPreview(); mMediaRecorder = new MediaRecorder(); onCameraOpened(); } catch (IllegalStateException e) { throwError(new Exception("Cannot access the camera.", e)); } catch (RuntimeException e2) { throwError(new Exception("Cannot access the camera, you may need to restart your device.", e2)); } } private Camera.Size getHighestSupportedStillShotSize(List<Camera.Size> supportedPictureSizes) { Collections.sort(supportedPictureSizes, new Comparator<Camera.Size>() { @Override public int compare(Camera.Size lhs, Camera.Size rhs) { if (lhs.height * lhs.width > rhs.height * rhs.width) return -1; return 1; } }); Camera.Size maxSize = supportedPictureSizes.get(0); Log.d("CameraFragment", "Using resolution: " + maxSize.width + "x" + maxSize.height); return maxSize; } @SuppressWarnings("WrongConstant") private void setCameraDisplayOrientation(Camera.Parameters parameters) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(getCurrentCameraId(), info); final int deviceOrientation = Degrees.getDisplayRotation(getActivity()); mDisplayOrientation = Degrees.getDisplayOrientation( info.orientation, deviceOrientation, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT); mCamera.setDisplayOrientation(90); } private void createPreview() { Activity activity = getActivity(); if (activity == null) return; if (mWindowSize == null) mWindowSize = new Point(); activity.getWindowManager().getDefaultDisplay().getSize(mWindowSize); mPreviewView = new CameraPreview(getActivity(), mCamera); // if (mPreviewFrame.getChildCount() > 0 && mPreviewFrame.getChildAt(0) instanceof CameraPreview) // mPreviewFrame.removeViewAt(0); // mPreviewFrame.addView(mPreviewView, 0); if (body.getChildCount() > 0 && body.getChildAt(0) instanceof CameraPreview) body.removeViewAt(0); // RelativeLayout.LayoutParams layoutParams= new RelativeLayout.LayoutParams( // RelativeLayout.LayoutParams.WRAP_CONTENT, // RelativeLayout.LayoutParams.WRAP_CONTENT); // layoutParams.addRule(RelativeLayout.BELOW,R.id.top); // layoutParams.addRule(RelativeLayout.ABOVE,R.id.controlsFrame); // mPreviewView.setLayoutParams(layoutParams); body.addView(mPreviewView, 0); mPreviewView.setAspectRatio(videoHeight, videoWidth); // mPreviewView.setAspectRatio(240, 320); // mPreviewView.setAspectRatio(mWindowSize.x, mWindowSize.y); } @Override public void closeCamera() { try { if (mCamera != null) { try { mCamera.lock(); } catch (Throwable ignored) { } mCamera.release(); mCamera = null; } } catch (IllegalStateException e) { throwError(new Exception("Illegal state while trying to close camera.", e)); } } private boolean prepareMediaRecorder() { try { if (mCamera==null){ openCamera(); } final Activity activity = getActivity(); if (null == activity) return false; final BaseCaptureInterface captureInterface = (BaseCaptureInterface) activity; setCameraDisplayOrientation(mCamera.getParameters()); mMediaRecorder = new MediaRecorder(); mCamera.stopPreview(); mCamera.unlock(); mMediaRecorder.setCamera(mCamera); boolean canUseAudio = true; boolean audioEnabled = !mInterface.audioDisabled(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) canUseAudio = ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED; if (canUseAudio && audioEnabled) { mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); } else if (audioEnabled) { Toast.makeText(getActivity(), R.string.mcam_no_audio_access, Toast.LENGTH_LONG).show(); } mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); final CamcorderProfile profile = CamcorderProfile.get(getCurrentCameraId(), mInterface.qualityProfile()); mMediaRecorder.setOutputFormat(profile.fileFormat); Log.e("lzf_type", "CameraFragment"); mMediaRecorder.setVideoEncodingBitRate(1000000); mMediaRecorder.setVideoFrameRate(30); mMediaRecorder.setVideoSize(videoWidth, videoHeight); // mMediaRecorder.setVideoSize(320, 240); // mMediaRecorder.setVideoSize(mVideoSize.width, mVideoSize.height); // mMediaRecorder.setVideoFrameRate(mInterface.videoFrameRate(profile.videoFrameRate)); // mMediaRecorder.setVideoEncodingBitRate(mInterface.videoEncodingBitRate(profile.videoBitRate)); mMediaRecorder.setVideoEncoder(profile.videoCodec); if (canUseAudio && audioEnabled) { mMediaRecorder.setAudioEncodingBitRate(mInterface.audioEncodingBitRate(profile.audioBitRate)); mMediaRecorder.setAudioChannels(profile.audioChannels); mMediaRecorder.setAudioSamplingRate(profile.audioSampleRate); mMediaRecorder.setAudioEncoder(profile.audioCodec); } Uri uri = Uri.fromFile(getOutputMediaFile()); mOutputUri = uri.toString(); mMediaRecorder.setOutputFile(uri.getPath()); if (captureInterface.maxAllowedFileSize() > 0) { mMediaRecorder.setMaxFileSize(captureInterface.maxAllowedFileSize()); mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { @Override public void onInfo(MediaRecorder mediaRecorder, int what, int extra) { if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) { Toast.makeText(getActivity(), R.string.mcam_file_size_limit_reached, Toast.LENGTH_SHORT).show(); stopRecordingVideo(false); } } }); } //横屏 //前摄像头拍摄 视频对称 //后摄像头拍摄 正常 int orient = getActivity().getRequestedOrientation(); int orientation=getActivity().getResources().getConfiguration().orientation; Log.e("lzf_orient", orient + " 当前屏幕方向 "+orientation); //固定屏幕方向 if (getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { mMediaRecorder.setOrientationHint(0); } else if (getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { //只走竖屏 if (mInterface.getCurrentCameraPosition() == BaseCaptureActivity.CAMERA_POSITION_BACK) { mMediaRecorder.setOrientationHint(90); } else { mMediaRecorder.setOrientationHint(270);//竖屏 //前摄像头拍摄 视频对称 } } Log.e("lzf_position", mInterface.getCurrentCameraPosition() + " 当前相机 "); // mMediaRecorder.setOrientationHint(90);//竖屏 //后摄像头拍摄 正常 // mMediaRecorder.setOrientationHint(270);//竖屏 //前摄像头拍摄 视频对称 mMediaRecorder.setPreviewDisplay(mPreviewView.getHolder().getSurface()); try { mMediaRecorder.prepare(); return true; } catch (Throwable e) { throwError(new Exception("Failed to prepare the media recorder: " + e.getMessage(), e)); return false; } } catch (Throwable t) { try { if (mCamera!=null) { mCamera.lock(); } } catch (IllegalStateException e) { throwError(new Exception("Failed to re-lock camera: " + e.getMessage(), e)); return false; } t.printStackTrace(); throwError(new Exception("Failed to begin recording: " + t.getMessage(), t)); return false; } } @Override public boolean startRecordingVideo() { super.startRecordingVideo(); CaptureActivity activity= (CaptureActivity) getActivity(); if (activity.isCanShowGuide()){ showPopupWindow(); } if (prepareMediaRecorder()) { try { // UI setImageRes(mButtonVideo, mInterface.iconStop()); if (!CameraUtil.isChromium()) mButtonFacing.setVisibility(View.GONE); // Only start counter if count down wasn't already started if (!mInterface.hasLengthLimit()) { mInterface.setRecordingStart(System.currentTimeMillis()); startCounter(); } // Start recording mMediaRecorder.start(); mButtonVideo.setEnabled(false); mButtonVideo.postDelayed(new Runnable() { @Override public void run() { mButtonVideo.setEnabled(true); } }, 200); return true; } catch (Throwable t) { t.printStackTrace(); mInterface.setRecordingStart(-1); stopRecordingVideo(false); throwError(new Exception("Failed to start recording: " + t.getMessage(), t)); } } return false; } @Override public void stopRecordingVideo(final boolean reachedZero) { super.stopRecordingVideo(reachedZero); if (mInterface.hasLengthLimit() && mInterface.shouldAutoSubmit() && (mInterface.getRecordingStart() < 0 || mMediaRecorder == null)) { stopCounter(); if (mCamera != null) { try { mCamera.lock(); } catch (Throwable t) { t.printStackTrace(); } } releaseRecorder(); closeCamera(); mReachedZero=reachedZero; return; } if (mCamera != null) mCamera.lock(); releaseRecorder(); closeCamera(); if (!mInterface.didRecord()) mOutputUri = null; setImageRes(mButtonVideo, mInterface.iconRecord()); if (!CameraUtil.isChromium()) mButtonFacing.setVisibility(View.VISIBLE); if (mInterface.getRecordingStart() > -1 && getActivity() != null) mReachedZero=reachedZero; stopCounter(); } @Override public void showPreView() { super.showPreView(); mInterface.onShowPreview(this,mOutputUri, mReachedZero); } private void setupFlashMode() { String flashMode = null; switch (mInterface.getFlashMode()) { case FLASH_MODE_AUTO: flashMode = Camera.Parameters.FLASH_MODE_AUTO; break; case FLASH_MODE_ALWAYS_ON: flashMode = Camera.Parameters.FLASH_MODE_ON; break; case FLASH_MODE_OFF: flashMode = Camera.Parameters.FLASH_MODE_OFF; default: break; } if (flashMode != null) { Camera.Parameters parameters = mCamera.getParameters(); parameters.setFlashMode(flashMode); mCamera.setParameters(parameters); } } @Override public void onPreferencesUpdated() { setupFlashMode(); } @Override public void takeStillshot() { Camera.ShutterCallback shutterCallback = new Camera.ShutterCallback() { public void onShutter() { //Log.d(TAG, "onShutter'd"); } }; Camera.PictureCallback rawCallback = new Camera.PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { //Log.d(TAG, "onPictureTaken - raw. Raw is null: " + (data == null)); } }; Camera.PictureCallback jpegCallback = new Camera.PictureCallback() { public void onPictureTaken(final byte[] data, Camera camera) { //Log.d(TAG, "onPictureTaken - jpeg, size: " + data.length); final File outputPic = getOutputPictureFile(); // lets save the image to disk ImageUtil.saveToDiskAsync(data, outputPic, new ICallback() { @Override public void done(Exception e) { if (e == null) { Log.d("CameraFragment", "Picture saved to disk - jpeg, size: " + data.length); mOutputUri = Uri.fromFile(outputPic).toString(); mInterface.onShowStillshot(mOutputUri); //mCamera.startPreview(); mButtonStillshot.setEnabled(true); } else { throwError(e); } } }); } }; // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { // // We could have configurable shutter sound here // mCamera.enableShutterSound(false); // } mButtonStillshot.setEnabled(false); mCamera.takePicture(shutterCallback, rawCallback, jpegCallback); } static class CompareSizesByArea implements Comparator<Camera.Size> { @Override public int compare(Camera.Size lhs, Camera.Size rhs) { // We cast here to ensure the multiplications won't overflow return Long.signum((long) lhs.width * lhs.height - (long) rhs.width * rhs.height); } } }