package com.camnter.newlife.utils.camera;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.camnter.newlife.R;
import com.camnter.newlife.core.activity.BaseActivity;
import com.camnter.newlife.utils.BitmapUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.UUID;
/**
* Description:IdCardCameraActivity
* Created by:CaMnter
*/
public class IdCardCameraActivity extends BaseActivity implements
SurfaceHolder.Callback,
Camera.PictureCallback,
CameraPreviewView.PreviewListener {
private static final String DEFAULT_PACKAGE_NAME = "AndroidLife";
private static final String DEFAULT_PICTURE_EXTENSION_NAME = ".jpg";
private static final String INTENT_EXTRA_KEY_PROMPT_VIEW_TYPE
= "intent_extra_key_prompt_view_type";
public static final String RESULT_DATA_KEY_WATER_MARK_BITMAP_PATH
= "result_data_key_water_mark_bitmap_path";
private static final int LAYOUT_TYPE_TAKE_PICTURE = 0x261;
private static final int LAYOUT_TYPE_PICTURE_PREVIEW = 0x262;
@IntDef({ LAYOUT_TYPE_TAKE_PICTURE, LAYOUT_TYPE_PICTURE_PREVIEW })
@Retention(RetentionPolicy.SOURCE)
public @interface LayoutType {
}
public static final int PROMPT_FRONT = 0x261;
public static final int PROMPT_REVERSE = 0x262;
@IntDef({ PROMPT_FRONT, PROMPT_REVERSE })
@Retention(RetentionPolicy.SOURCE)
public @interface PromptViewType {
}
@PromptViewType
private int promptViewType;
@BindView(R.id.id_card_camera_surface_view)
SurfaceView cameraSurfaceView;
@BindView(R.id.id_card_surface_preview)
CameraPreviewView surfacePreview;
@BindView(R.id.id_card_camera_operation_layout)
RelativeLayout cameraOperationLayout;
@BindView(R.id.id_card_camera_top_bar_layout)
FrameLayout topBarLayout;
@BindView(R.id.id_card_camera_light_image)
ImageView lightImage;
@BindView(R.id.id_card_prompt_front_image)
ImageView promptFrontImage;
@BindView(R.id.id_card_prompt_reverse_image)
ImageView promptReverseImage;
@BindView(R.id.id_card_preview_operation_layout)
RelativeLayout previewOperationLayout;
@BindView(R.id.id_card_preview_image)
ImageView previewImage;
private CameraManager cameraManager;
private boolean hasSurface;
private boolean openLight;
private boolean isTaking;
// 用于缓存最后一次 takePicture 的 bitmap(带水印)
private Bitmap watermarkBitmap;
public static void startActivityForResult(@NonNull final Activity activity,
@PromptViewType final int promptViewType,
final int requestCode) {
Intent intent = new Intent(activity, IdCardCameraActivity.class);
intent.putExtra(INTENT_EXTRA_KEY_PROMPT_VIEW_TYPE, promptViewType);
activity.startActivityForResult(intent, requestCode);
}
/**
* Fill in layout id
*
* @return layout id
*/
@Override protected int getLayoutId() {
return R.layout.activity_id_card_camera;
}
/**
* Initialize the view in the layout
*
* @param savedInstanceState savedInstanceState
*/
@Override protected void initViews(Bundle savedInstanceState) {
ButterKnife.bind(this);
}
/**
* Initialize the View of the listener
*/
@Override protected void initListeners() {
this.surfacePreview.setPreviewListener(this);
}
/**
* Initialize the Activity data
*/
@Override protected void initData() {
this.promptViewType =
this.getIntent().getIntExtra(INTENT_EXTRA_KEY_PROMPT_VIEW_TYPE, PROMPT_FRONT) ==
PROMPT_FRONT ?
PROMPT_FRONT : PROMPT_REVERSE;
this.surfacePreview.setPromptViewType(this.promptViewType);
this.surfacePreview.setDrawMode(CameraPreviewView.DRAW_MODE_BY_DRAWABLE);
}
@Override
protected void onResume() {
super.onResume();
this.initCameraSurface();
}
private void initCameraSurface() {
this.cameraManager = CameraManager.getInstance();
SurfaceHolder holder = this.cameraSurfaceView.getHolder();
if (this.hasSurface) {
// activity 在 paused 时但不会 stopped,因此 surface 仍旧存在;
// surfaceCreated() 不会调用,因此在这里初始化 camera
// this.initCamera(holder);
} else {
// 重置 callback,等待 surfaceCreated() 来初始化camera
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
@Override
protected void onPause() {
super.onPause();
this.cameraManager.stopPreview();
this.cameraManager.closeCamera();
if (this.hasSurface) return;
SurfaceHolder holder = this.cameraSurfaceView.getHolder();
holder.removeCallback(this);
}
private void initCamera(SurfaceHolder holder, int surfaceViewWidth, int surfaceViewHeight) {
if (holder == null) return;
try {
this.cameraManager.openCamera(this, holder, surfaceViewWidth, surfaceViewHeight);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
this.cameraManager.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (this.hasSurface) return;
this.hasSurface = true;
this.initCamera(holder, this.cameraSurfaceView.getWidth(),
this.cameraSurfaceView.getHeight());
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (!this.hasSurface) return;
this.hasSurface = false;
this.cameraManager.stopPreview();
}
@Override
public void notificationFrontImageView(int frontImageMarginTop, int frontImageMarginLeft) {
this.promptFrontImage.setVisibility(View.VISIBLE);
RelativeLayout.LayoutParams layoutParams
= (RelativeLayout.LayoutParams) this.promptFrontImage.getLayoutParams();
layoutParams.setMargins(frontImageMarginLeft, frontImageMarginTop, 0, 0);
this.promptFrontImage.setLayoutParams(layoutParams);
}
@Override
public void notificationReverseImageView(int reverseImageMarginTop, int reverseImageMarginLeft) {
this.promptReverseImage.setVisibility(View.VISIBLE);
RelativeLayout.LayoutParams layoutParams
= (RelativeLayout.LayoutParams) this.promptReverseImage.getLayoutParams();
layoutParams.setMargins(reverseImageMarginLeft, reverseImageMarginTop, 0, 0);
this.promptReverseImage.setLayoutParams(layoutParams);
}
@OnClick({ R.id.id_card_camera_take_image,
R.id.id_card_camera_light_image,
R.id.id_card_preview_reset_text,
R.id.id_card_preview_confirm_text,
R.id.id_card_camera_close_image })
public void onClick(View view) {
switch (view.getId()) {
case R.id.id_card_camera_take_image:
if (this.isTaking) return;
this.cameraManager.takePicture(null, null, this);
break;
case R.id.id_card_camera_light_image:
if (this.openLight) {
this.openLight = false;
this.cameraManager.closeLight();
this.lightImage.setImageResource(R.drawable.icon_camera_light_close);
} else {
this.openLight = true;
this.cameraManager.openLight();
this.lightImage.setImageResource(R.drawable.icon_camera_light_open);
}
break;
case R.id.id_card_preview_reset_text:
this.switchLayoutType(LAYOUT_TYPE_TAKE_PICTURE);
this.watermarkBitmap = null;
break;
case R.id.id_card_preview_confirm_text:
final String picturePath = this.createPicturePath();
new FileSaveTask(this.getApplicationContext(), picturePath).execute(
this.watermarkBitmap);
final Intent data = new Intent();
data.putExtra(RESULT_DATA_KEY_WATER_MARK_BITMAP_PATH, picturePath);
this.setResult(RESULT_OK, data);
this.finish();
break;
case R.id.id_card_camera_close_image:
this.finish();
break;
}
}
private String createPicturePath() {
return Environment.getExternalStorageDirectory().getAbsoluteFile() +
File.separator +
DEFAULT_PACKAGE_NAME +
File.separator +
UUID.randomUUID().toString() +
DEFAULT_PICTURE_EXTENSION_NAME;
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
final BitmapFactory.Options tempOptions = new BitmapFactory.Options();
tempOptions.inJustDecodeBounds = false;
final Bitmap originalBitmap = BitmapFactory.decodeByteArray(data, 0, data.length,
tempOptions);
// 压缩
final Bitmap expectBitmap = this.cameraManager.compressForIdCard(originalBitmap);
// 水印
this.watermarkBitmap = this.cameraManager.addWatermarkBitmap(this,
expectBitmap,
R.drawable.ic_camnter);
// 旋转后的图片记录,为了在确认的时候保存
final Bitmap previewBitmap = BitmapUtils.rotate(watermarkBitmap, 90.f);
this.previewImage.setImageBitmap(previewBitmap);
this.showToast("拍照成功", Toast.LENGTH_SHORT);
this.cameraManager.mustPreview();
this.isTaking = false;
this.switchLayoutType(LAYOUT_TYPE_PICTURE_PREVIEW);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
private void switchLayoutType(@LayoutType final int layoutType) {
switch (layoutType) {
case LAYOUT_TYPE_TAKE_PICTURE:
this.cameraSurfaceView.setVisibility(View.VISIBLE);
this.surfacePreview.setVisibility(View.VISIBLE);
this.cameraOperationLayout.setVisibility(View.VISIBLE);
this.topBarLayout.setVisibility(View.VISIBLE);
this.previewImage.setVisibility(View.GONE);
this.previewOperationLayout.setVisibility(View.GONE);
break;
case LAYOUT_TYPE_PICTURE_PREVIEW:
// close light
this.cameraManager.closeLight();
this.lightImage.setImageResource(this.cameraManager.isLightOpen() ?
R.drawable.icon_camera_light_open :
R.drawable.icon_camera_light_close);
this.cameraSurfaceView.setVisibility(View.GONE);
this.surfacePreview.setVisibility(View.GONE);
this.cameraOperationLayout.setVisibility(View.GONE);
this.topBarLayout.setVisibility(View.GONE);
this.previewImage.setVisibility(View.VISIBLE);
this.previewOperationLayout.setVisibility(View.VISIBLE);
break;
}
}
private static class FileSaveTask extends AsyncTask<Bitmap, Object, String[]> {
private final String picturePath;
private final WeakReference<Context> contextWeakReference;
private FileSaveTask(Context context, String picturePath) {
this.contextWeakReference = new WeakReference<>(context);
this.picturePath = picturePath;
}
@Override
protected String[] doInBackground(Bitmap... params) {
if (params == null || params.length == 0) return null;
return this.savePicture(this.picturePath, params[0]);
}
@Override
protected void onPostExecute(String[] results) {
Context context;
if (results == null || (context = this.contextWeakReference.get()) == null) return;
if (results.length < 2) return;
this.notificationMediaStore(context, results[0], results[1]);
}
/**
* @param picturePath picturePath
* @param expectBitmap expectBitmap
* @return absolutePath , name
*/
public String[] savePicture(@NonNull final String picturePath,
@NonNull final Bitmap expectBitmap) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File expectFile = new File(picturePath);
if (!expectFile.getParentFile().exists()) {
boolean mkdirsSuccess = expectFile.mkdirs();
if (!mkdirsSuccess) return null;
}
try {
FileOutputStream outStream = new FileOutputStream(expectFile);
expectBitmap.compress(Bitmap.CompressFormat.JPEG,
100, outStream);
outStream.flush();
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return new String[] { expectFile.getAbsolutePath(), expectFile.getName() };
} else {
return null;
}
}
private void notificationMediaStore(@NonNull final Context context,
@NonNull final String absolutePath,
@NonNull final String fileName) {
final String path = "file://" + absolutePath;
// 其次把文件插入到系统图库
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
path, fileName, null);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
// 最后通知图库更新
context.sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(path)));
}
}
}