package com.example.ju_net;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.MediaStore;
//import android.support.annotation.NonNull;
//import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> activityResultLauncher;
private static final int CODE_SELECT_IMAGE = 1;
private CameraManager mCameraManager;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceViewHolder;
private Handler mHandler;
private String mCameraId;
private ImageReader mImageReader;
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewBuilder;
private CameraCaptureSession mSession;
private RecyclerView recyclerView;
private PhotoAdapter photoAdapter;
private List<String> photoPaths = new ArrayList<>();
private Button take_picture_bt, mOpenPhoto, mUploadPhoto;
private Handler mainHandler;
private static final String TAG = "CameraFragment";
private String mPublicPhotoPath = "";
//创建okHttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
recyclerView = findViewById(R.id.recycler_view);
// img_show = (ImageView) findViewById(R.id.img_show);
take_picture_bt = (Button) findViewById(R.id.take_picture);
mOpenPhoto = (Button) findViewById(R.id.open_photo);
mUploadPhoto = (Button) findViewById(R.id.upload_photo);
mUploadPhoto.setEnabled(false);
// 初始化RecyclerView
photoAdapter = new PhotoAdapter(this, photoPaths);
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
recyclerView.setAdapter(photoAdapter);
// 注册 Activity Result Launcher
activityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> handleGalleryResult(result)
);
initSurfaceView();//初始化SurfaceView
/**
* 拍照按钮监听
*/
take_picture_bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
takePicture();
}
});
mOpenPhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);
albumIntent.setType("image/*");
albumIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); // 允许多选
activityResultLauncher.launch(albumIntent);
}
});
mUploadPhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 通过AlertDialog.Builder这个类来实例化我们的一个AlertDialog的对象
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
// 设置Title的图标
builder.setIcon(R.drawable.ic_launcher_background);
// 设置Title的内容
builder.setTitle("提示框");
// 设置Content来显示一个信息
builder.setMessage("确定上传吗?");
// 设置一个PositiveButton
builder.setPositiveButton("确定", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
Log.i(TAG, mPublicPhotoPath);
if (mPublicPhotoPath == "") {
return;
}
File file = new File(mPublicPhotoPath);
Request request = getFileRequest("http://192.168.11.13:10004/api/upload", file, null);
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.i(TAG, "上传失败!");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
parseJSONWithGSON(result);
//显示UI界面,调用的showResponse方法
Log.i(TAG, result.toString());
//Toast.makeText(MainActivity.this, "success!", Toast.LENGTH_SHORT).show();
}
});
}
});
// 设置一个NegativeButton
builder.setNegativeButton("取消", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
//Toast.makeText(MainActivity.this, "negative: " + which, Toast.LENGTH_SHORT).show();
}
});
// 设置一个NeutralButton
// 显示出该对话框
builder.show();
}
});
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
}
private void handleGalleryResult(ActivityResult result) {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
Intent data = result.getData();
if (data.getClipData() != null) { // 多选
ClipData clipData = data.getClipData();
for (int i = 0; i < clipData.getItemCount(); i++) {
Uri imageUri = clipData.getItemAt(i).getUri();
String path = getRealPathFromURI(imageUri);
if (!photoPaths.contains(path)) {
photoPaths.add(path);
}
}
} else if (data.getData() != null) { // 单选
Uri imageUri = data.getData();
String path = getRealPathFromURI(imageUri);
if (!photoPaths.contains(path)) {
photoPaths.add(path);
}
}
photoAdapter.notifyDataSetChanged();
}
}
private String getRealPathFromURI(Uri contentUri) {
Cursor cursor = getContentResolver().query(contentUri, null, null, null, null);
if (cursor == null) return contentUri.getPath();
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
String path = cursor.getString(idx);
cursor.close();
return path;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 1){
for (int grantResult : grantResults) {
if(grantResult != PackageManager.PERMISSION_GRANTED){
Toast.makeText(this, "对不起,没有权限,无法正常使用相机", Toast.LENGTH_SHORT).show();
return;
}else{
System.out.println("正常使用相机!");
}
}
initCameraAndPreview();
}
}
public void initSurfaceView() {
mSurfaceView = (SurfaceView) findViewById(R.id.mFirstSurfaceView);
mSurfaceViewHolder = mSurfaceView.getHolder();//通过SurfaceViewHolder可以对SurfaceView进行管理
mSurfaceViewHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
initCameraAndPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//释放camera
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
}
@TargetApi(19)
public void initCameraAndPreview() {
HandlerThread handlerThread = new HandlerThread("My First Camera2");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
mainHandler = new Handler(getMainLooper());//用来处理ui线程的handler,即ui线程
mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
try {
mCameraId = "" + CameraCharacteristics.LENS_FACING_FRONT;
mImageReader = ImageReader.newInstance(mSurfaceView.getWidth(), mSurfaceView.getHeight(), ImageFormat.JPEG,/*maxImages*/7);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mainHandler);//这里必须传入mainHandler,因为涉及到了Ui操作
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
|| checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{android.Manifest.permission.CAMERA, android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
return;
}
mCameraManager.openCamera(mCameraId, deviceStateCallback, mHandler);
} catch (CameraAccessException e) {
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
}
}
private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
//进行相片存储
//mCameraDevice.close();
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);//将image对象转化为byte,再转化为bitmap
final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (bitmap != null) {
//img_show.setImageBitmap(bitmap);
mUploadPhoto.setEnabled(true);
}
savePicture(bytes);
}
};
private CameraDevice.StateCallback deviceStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCameraDevice = camera;
try {
takePreview();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
@Override
public void onError(CameraDevice camera, int error) {
Toast.makeText(MainActivity.this, "打开摄像头失败", Toast.LENGTH_SHORT).show();
}
};
public void takePreview() throws CameraAccessException {
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewBuilder.addTarget(mSurfaceViewHolder.getSurface());
mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceViewHolder.getSurface(), mImageReader.getSurface()), mSessionPreviewStateCallback, mHandler);
}
private CameraCaptureSession.StateCallback mSessionPreviewStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
mSession = session;
//配置完毕开始预览
try {
/**
* 设置你需要配置的参数
*/
//自动对焦
mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
//打开闪光灯
mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
//无限次的重复获取图像
mSession.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Toast.makeText(MainActivity.this, "配置失败", Toast.LENGTH_SHORT).show();
}
};
public void takePicture() {
try {
CaptureRequest.Builder captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);//用来设置拍照请求的request
captureRequestBuilder.addTarget(mImageReader.getSurface());
// 自动对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 自动曝光
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getJpegOrientation(cameraCharacteristics, rotation));//使图片做顺时针旋转
CaptureRequest mCaptureRequest = captureRequestBuilder.build();
mSession.capture(mCaptureRequest, null, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
//获取图片应该旋转的角度,使图片竖直
public int getOrientation(int rotation) {
switch (rotation) {
case Surface.ROTATION_0:
return 90;
case Surface.ROTATION_90:
return 0;
case Surface.ROTATION_180:
return 270;
case Surface.ROTATION_270:
return 180;
default:
return 0;
}
}
//获取图片应该旋转的角度,使图片竖直
private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN)
return 0;
int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Round device orientation to a multiple of 90
deviceOrientation = (deviceOrientation + 45) / 90 * 90;
// LENS_FACING相对于设备屏幕的方向,LENS_FACING_FRONT相机设备面向与设备屏幕相同的方向
boolean facingFront = c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT;
if (facingFront) deviceOrientation = -deviceOrientation;
// Calculate desired JPEG orientation relative to camera orientation to make
// the image upright relative to the device orientation
int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;
return jpegOrientation;
}
//将照片存储在相机照片存储位置,这里采用bitmap方式保存
public String savePicture(byte[] imgBytes) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
String imgPath = Environment.getExternalStorageDirectory() + "/DCIM/JPEG_" + timeStamp + ".jpg";
try (FileOutputStream outputStream = new FileOutputStream(imgPath)) {
outputStream.write(imgBytes);
photoPaths.add(imgPath);
photoAdapter.notifyDataSetChanged();
MediaScannerConnection.scanFile(this, new String[]{imgPath}, null, null);
} catch (IOException e) {
e.printStackTrace();
}
return timeStamp;
}
public static Request getFileRequest(String url, File file, Map<String, String> maps){
MultipartBody.Builder builder= new MultipartBody.Builder().setType(MultipartBody.FORM);
if(maps==null){
builder.addPart( Headers.of("Content-Disposition", "form-data; name=\"file\";filename=\"file.jpg\""), RequestBody.create(MediaType.parse("image/png"),file)
).build();
}else{
for (String key : maps.keySet()) {
builder.addFormDataPart(key, maps.get(key));
}
builder.addPart( Headers.of("Content-Disposition", "form-data; name=\"file\";filename=\"file.jpg\""), RequestBody.create(MediaType.parse("image/png"),file)
);
}
RequestBody body=builder.build();
return new Request.Builder().url(url).post(body).build();
}
private void parseJSONWithGSON(String jsonData) {
//使用轻量级的Gson解析得到的json
Gson gson = new Gson();
UploadResult uploadResult = gson.fromJson(jsonData, new TypeToken<UploadResult>() {}.getType());
//控制台输出结果,便于查看
Log.d("MainActivity", "status" + uploadResult.getStatus());
Log.d("MainActivity", "msg" + uploadResult.getMsg());
}
}逐段分析所有代码