问题
My application was working good in large number of phones. However, when I installed it in my old android phone the following error is thrown and application crashes while taking the photo.
Android java.lang.IllegalArgumentException: previewSize must not be taller than activeArray
Photo Capturing code:
public class Camera1 extends AppCompatActivity {
private static final String TAG = "AndroidCameraApi";
private TextureView textureView;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private Bitmap scaled;
private Bitmap mBitmapToSave;
private Bitmap mBitmapToSave1;
private String cameraId;
protected CameraDevice cameraDevice;
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest captureRequest;
protected CaptureRequest.Builder captureRequestBuilder;
private Size imageDimension;
private ImageReader imageReader;
private File file;
private com.google.android.gms.vision.face.FaceDetector detector;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private boolean mFlashSupported;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
private int width = 640;
private int height = 480;
private int index;
//Image request code
private int PICK_IMAGE_REQUEST = 1;
private int a=0;
//storage permission code
private static final int STORAGE_PERMISSION_CODE = 123;
//Bitmap to get image from gallery
private Bitmap bitmap;
//Uri to store the image uri
private Uri filePath;
private String name,dl_no,truck_id, tstatus;
private float l_value;
private String dl;
private int c=0;
File fileToUpload;
int f=0;
private String uuid;
String latitude;
String longitude;
String time1;
String date1;
private int mSensorOrientation;
CameraCharacteristics characteristics;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_camera2_api);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
textureView = (TextureView) findViewById(R.id.texture);
assert textureView != null;
textureView.setSurfaceTextureListener(textureListener);
detector = new FaceDetector.Builder(getApplicationContext())
.setMode(FaceDetector.ACCURATE_MODE)
.build();
uuid = UUID.randomUUID().toString();
Bundle extras = getIntent().getExtras();
if (extras != null) {
l_value=extras.getFloat("v");
tstatus=extras.getString("status");
name=extras.getString("name");
dl_no=extras.getString("dl");
truck_id=extras.getString("tid");
latitude=extras.getString("lat");
longitude=extras.getString("lon");
time1 =extras.getString("t");
date1=extras.getString("d");
}
fileToUpload = new File(Environment.getExternalStorageDirectory() + "/" + "/Faceapp/"+name+"_"+dl_no+"_"+truck_id+"_"+latitude+"_"+longitude+"_"+time1+"_"+date1+"_"+a+".jpg");
//Intent uplaod_intent = new Intent(Camera1.this, uploadRest.class);
// Add extras to the bundle
// Start the service
// Camera1.this.startService(uplaod_intent);
}
private int getOrientation(int rotation) {
// Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X
// We have to take that into account and rotate JPEG properly.
// For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
// For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
//open your camera here
openCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Transform you image captured size according to the surface width and height
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
//This is called when the camera is open
Log.e(TAG, "onOpened");
cameraDevice = camera;
createCameraPreview();
}
@Override
public void onDisconnected(CameraDevice camera) {
cameraDevice.close();
}
@Override
public void onError(CameraDevice camera, int error) {
cameraDevice.close();
cameraDevice = null;
}
};
final CameraCaptureSession.CaptureCallback captureCallbackListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(Camera1.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
}
};
protected void startBackgroundThread() {
mBackgroundThread = new HandlerThread("Camera Background");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
protected void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void goToCompletedActivity(Context mContext) {
Intent login = new Intent(mContext, Completed.class);
mContext.startActivity(login);
}
private void userLogin() {
//first getting the values
final String Driver_id = dl_no;
class UserLogin extends AsyncTask<Void, Void, String> {
ProgressBar progressBar;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar = (ProgressBar) findViewById(R.id.progressBar);
//progressBar.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// progressBar.setVisibility(View.GONE);
try {
//converting response to json object
JSONObject obj = new JSONObject(s);
//if no error in response
if (!obj.getBoolean("error")) {
Toast.makeText(getApplicationContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
//getting the user from the response
JSONObject userJson = obj.getJSONObject("user");
//creating a new user object
User user = new User(
userJson.getString("Driver_id"),
userJson.getString("Driver_name"),
userJson.getString("Truck_id"),
userJson.getString("Trainingstatus")
);
//storing the user in shared preferences
SharedPrefManager.getInstance(getApplicationContext()).userLogin(user);
//starting the profile activity
finish();
startActivity(new Intent(getApplicationContext(), ProfileActivity.class));
} else {
Toast.makeText(getApplicationContext(), "Invalid Driver ID", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
protected String doInBackground(Void... voids) {
//creating request handler object
RequestHandler requestHandler = new RequestHandler();
//creating request parameters
HashMap<String, String> params = new HashMap<>();
params.put("Driver_id", Driver_id);
//returing the response
return requestHandler.sendPostRequest(URLs.URL_LOGIN, params);
}
}
UserLogin ul = new UserLogin();
ul.execute();
}
public void launchuploadservice() {
// Construct our Intent specifying the Service
Intent i = new Intent(this, Upload.class);
// Add extras to the bundle
i.putExtra("name", name);
i.putExtra("dl", dl_no);
i.putExtra("tid", truck_id);
i.putExtra("lat", latitude);
i.putExtra("lon", longitude);
i.putExtra("status", tstatus);
i.putExtra("t", time1);
i.putExtra("d", date1);
// Start the service
startService(i);
}
protected void takePicture() {
if (null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
return;
}
final CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
if (jpegSizes != null && 0 < jpegSizes.length) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int displayRotation = this.getWindowManager().getDefaultDisplay().getRotation();
int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (sensorOrientation == 90 || sensorOrientation == 270) {
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
swappedDimensions = true;
}
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (sensorOrientation == 0 || sensorOrientation == 180) {
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
swappedDimensions = true;
}
}
break;
}
int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null ;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
mBitmapToSave = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (detector.isOperational() && mBitmapToSave != null) {
Frame frame = new Frame.Builder()
.setBitmap(mBitmapToSave)
//.setImageData(buffer, width, height, YUV_420_888)
//.setRotation(getWindowManager().getDefaultDisplay().getRotation())
.build();
SparseArray<Face> faces = detector.detect(frame);
for (index = 0; index < faces.size(); ++index) {
Face face = faces.valueAt(index);
}
if (faces.size() == 0) {
Toast.makeText(Camera1.this, "No Face" + "\n", Toast.LENGTH_SHORT).show();
saveImageToDisk(bytes);
MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.not);
mediaPlayer.start();
// mBitmapToSave.recycle();
} else {
saveImageToDisk(bytes);
Toast.makeText(Camera1.this, "Face Found " + "\n", Toast.LENGTH_SHORT).show();
launchuploadservice();
}
}
} catch (Exception ee) {
}
finally {
if(image!=null)
image.close();
}
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
createCameraPreview();
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, mBackgroundHandler);
mBitmapToSave = null;
} catch(CameraAccessException e){
e.printStackTrace();
}
}
private void saveImageToDisk(final byte[] bytes) {
final File file = new File(Environment.getExternalStorageDirectory() + "/"+"/Faceapp/"+name+"_"+dl_no+"_"+truck_id+"_"+longitude+"_"+latitude+"_"+time1+"_"+date1 + "_.jpg");
try (final OutputStream output = new FileOutputStream(file)) {
output.write(bytes);
//this.picturesTaken.put(file.getPath(), bytes);
} catch (IOException e) {
Log.e(TAG, "Exception occurred while saving picture to external storage ", e);
}
}
protected void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback(){
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
//The camera is already closed
if (null == cameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(Camera1.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "is camera open");
try {
cameraId = manager.getCameraIdList()[1];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
// Add permission for camera and let user grant the permission
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(Camera1.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION);
return;
}
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e(TAG, "openCamera X");
}
protected void updatePreview() {
if(null == cameraDevice) {
Log.e(TAG, "updatePreview error, return");
}
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void closeCamera() {
if (null != cameraDevice) {
cameraDevice.close();
cameraDevice = null;
}
if (null != imageReader) {
//image.close();
imageReader.close();
imageReader = null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// close the app
Toast.makeText(Camera1.this, "Sorry!!!, you can't use this app without granting permission", Toast.LENGTH_LONG).show();
finish();
}
}
}
// @Override
/* public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// close the app
Toast.makeText(Camera1.this, "Sorry!!!, you can't use this app without granting permission", Toast.LENGTH_LONG).show();
finish();
}
}
}
*/
@Override
protected void onResume() {
final Intent intent = new Intent(Camera1.this, Completed.class);
super.onResume();
Log.e(TAG, "onResume");
startBackgroundThread();
if (textureView.isAvailable()) {
openCamera();
} else {
textureView.setSurfaceTextureListener(textureListener);
}
final int PICTURES_LIMIT = 1;
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
int pictureNo=0;
public void run() {
if (pictureNo>PICTURES_LIMIT){
timer.cancel();
finish();
} else {
takePicture();
pictureNo++;
}
}
},10, 5500);
}
@Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause");
closeCamera();
stopBackgroundThread();
}
}
回答1:
Based on the code found here, its pretty self explanatory that the old device preview size is less than the size that you're trying to crop.
Check the getPreviewCropRectangleUnzoomed
function in the code that I have mentioned above. The documentation of the function says the cause of the error specifically. From the documentation.
/**
* Calculate the effective crop rectangle for this preview viewport;
* assumes the preview is centered to the sensor and scaled to fit across one of the dimensions
* without skewing.
*
* <p>The preview size must be a subset of the active array size; the resulting
* rectangle will also be a subset of the active array rectangle.</p>
*
* <p>The unzoomed crop rectangle is calculated only.</p>
*
* @param activeArray active array dimensions, in sensor space
* @param previewSize size of the preview buffer render target, in pixels (not in sensor space)
* @return a rectangle which serves as the preview stream's effective crop region (unzoomed),
* in sensor space
*
* @throws NullPointerException
* if any of the args were {@code null}
* @throws IllegalArgumentException
* if {@code previewSize} is wider or taller than {@code activeArray}
*/
Check the part - The preview size must be a subset of the active array size; the resulting rectangle will also be a subset of the active array rectangle. which declares the preview size must be smaller than the actual active array size.
In this case, you might consider having a try/catch block while you are taking picture using the camera.
try {
takePicture();
} catch (IllegalArgumentException e) {
Toast.makeText(this, "Your phone is too old", Toast.LENGTH_SHORT).show();
}
Hope that helps.
回答2:
I believe that this may happen in very old devices with small image sensors, although seems to me (only guessing) more like a mistake by the manufacturer when they implemented the camera2 legacy wrapper.
A solution could be that when you are resolving the optimal preview size, then also to take into account that such preview size it doesn't exceed the size specified by SENSOR_INFO_ACTIVE_ARRAY_SIZE, which can be queried in the CameraCharacteristics:
CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE
来源:https://stackoverflow.com/questions/48942403/android-java-lang-illegalargumentexception-previewsize-must-not-be-taller-than