package nodomain.freeyourgadget.gadgetbridge.womp;
|
|
import android.Manifest;
|
import android.annotation.SuppressLint;
|
import android.content.Intent;
|
import android.content.pm.PackageManager;
|
import android.os.Bundle;
|
import android.util.Size;
|
import android.widget.TextView;
|
import android.widget.Toast;
|
|
import androidx.annotation.NonNull;
|
import androidx.annotation.Nullable;
|
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.camera.core.CameraSelector;
|
import androidx.camera.core.ImageAnalysis;
|
import androidx.camera.core.ImageProxy;
|
import androidx.camera.core.Preview;
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
import androidx.camera.view.PreviewView;
|
import androidx.core.app.ActivityCompat;
|
import androidx.core.content.ContextCompat;
|
|
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.zxing.BinaryBitmap;
|
import com.google.zxing.MultiFormatReader;
|
import com.google.zxing.NotFoundException;
|
import com.google.zxing.PlanarYUVLuminanceSource;
|
import com.google.zxing.Result;
|
import com.google.zxing.common.HybridBinarizer;
|
|
import java.nio.ByteBuffer;
|
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.Executors;
|
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
|
public class WompScanActivity extends AppCompatActivity {
|
public static final String EXTRA_CODE = "code";
|
private PreviewView previewView;
|
private ExecutorService cameraExecutor;
|
private volatile boolean found;
|
private final MultiFormatReader reader = new MultiFormatReader();
|
|
@Override
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
setTheme(R.style.GadgetbridgeTheme_NoActionBar);
|
super.onCreate(savedInstanceState);
|
setContentView(R.layout.activity_womp_scan);
|
previewView = findViewById(R.id.womp_preview);
|
TextView hint = findViewById(R.id.womp_scan_hint);
|
hint.setText("对准二维码扫描");
|
cameraExecutor = Executors.newSingleThreadExecutor();
|
findViewById(R.id.womp_scan_cancel).setOnClickListener(v -> {
|
setResult(RESULT_CANCELED);
|
finish();
|
});
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
|
} else {
|
startCamera();
|
}
|
}
|
|
@Override
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
startCamera();
|
} else {
|
Toast.makeText(this, "需要摄像头权限", Toast.LENGTH_SHORT).show();
|
finish();
|
}
|
}
|
|
private void startCamera() {
|
ListenableFuture<ProcessCameraProvider> future = ProcessCameraProvider.getInstance(this);
|
future.addListener(() -> {
|
try {
|
ProcessCameraProvider provider = future.get();
|
Preview preview = new Preview.Builder().build();
|
preview.setSurfaceProvider(previewView.getSurfaceProvider());
|
ImageAnalysis analysis = new ImageAnalysis.Builder()
|
.setTargetResolution(new Size(1280, 720))
|
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
.build();
|
analysis.setAnalyzer(cameraExecutor, this::analyze);
|
provider.unbindAll();
|
provider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, preview, analysis);
|
} catch (Exception e) {
|
Toast.makeText(this, "无法打开摄像头", Toast.LENGTH_SHORT).show();
|
finish();
|
}
|
}, ContextCompat.getMainExecutor(this));
|
}
|
|
@SuppressLint("UnsafeOptInUsageError")
|
private void analyze(ImageProxy image) {
|
if (found) {
|
image.close();
|
return;
|
}
|
try {
|
ImageProxy.PlaneProxy plane = image.getPlanes()[0];
|
ByteBuffer buffer = plane.getBuffer();
|
int width = image.getWidth();
|
int height = image.getHeight();
|
int rowStride = plane.getRowStride();
|
byte[] data = new byte[width * height];
|
if (rowStride == width) {
|
buffer.get(data, 0, Math.min(data.length, buffer.remaining()));
|
} else {
|
byte[] row = new byte[rowStride];
|
int pos = 0;
|
for (int i = 0; i < height; i++) {
|
int toRead = Math.min(rowStride, buffer.remaining());
|
if (toRead <= 0) break;
|
buffer.get(row, 0, toRead);
|
System.arraycopy(row, 0, data, pos, width);
|
pos += width;
|
}
|
}
|
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
|
data, width, height, 0, 0, width, height, false);
|
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
Result result = reader.decodeWithState(bitmap);
|
if (result != null && result.getText() != null) {
|
found = true;
|
Intent dataIntent = new Intent();
|
dataIntent.putExtra(EXTRA_CODE, result.getText().trim());
|
setResult(RESULT_OK, dataIntent);
|
finish();
|
}
|
} catch (NotFoundException ignored) {
|
} catch (Exception ignored) {
|
} finally {
|
reader.reset();
|
image.close();
|
}
|
}
|
|
@Override
|
protected void onDestroy() {
|
super.onDestroy();
|
if (cameraExecutor != null) {
|
cameraExecutor.shutdown();
|
}
|
}
|
}
|