I have a problem on my Android app. I'm using MediaStore.ACTION_IMAGE_CAPTURE intent to take picture from camera. It worked all most of devices but I got the following crash errors on DroidX device from android market.
I think imageCaptureUri can not be null in this case. So it is not the cause.
Do you have any ideas? Is it a firmware error?
java.lang.NullPointerException at
android.content.ContentResolver.openInputStream(ContentResolver.java:286)
at
com.eb.android.activity.AddActivity.getBase64Receipt(AddActivity.java:193)
at
com.eb.android.activity.AddActivity.publishReceipt(AddActivity.java:204)
at com.eb.android.activity.AddActivity.access$0(AddActivity.java:203)
at com.eb.android.activity.AddActivity$1.run(AddActivity.java:50) at
java.lang.Thread.run(Thread.java:1102)
java.lang.NullPointerException at
android.content.ContentResolver.openInputStream(ContentResolver.java:288)
at
com.eb.android.activity.AddActivity.getBase64Receipt(AddActivity.java:193)
at
com.eb.android.activity.AddActivity.publishReceipt(AddActivity.java:204)
at com.eb.android.activity.AddActivity.access$0(AddActivity.java:203)
at com.eb.android.activity.AddActivity$1.run(AddActivity.java:50) at
java.lang.Thread.run(Thread.java:1096)
This is my implementation:
public class AddActivity extends Activity {
public static final int TAKE_RECEIPT = 2;
private Uri imageCaptureUri;
private Runnable submitReceiptRunnable = new Runnable() {
public void run() {
publishReceipt();
}
};
private ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add);
registerListeners();
}
public void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
switch (reqCode) {
case (TAKE_RECEIPT):
takeReceiptCallback(resultCode, data);
break;
}
}
private void registerListeners() {
ImageView addReceiptButton = (ImageView) findViewById(R.id.AddReceiptButton);
addReceiptButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
takePictureFromCamera();
}
});
}
private void takePictureFromCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
imageCaptureUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "tmp_receipt_"
+ String.valueOf(System.currentTimeMillis()) + ".jpg"));
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageCaptureUri);
intent.putExtra("return-data", true);
startActivityForResult(intent, TAKE_RECEIPT);
}
private void takeReceiptCallback(int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
submitReceipt();
}
}
private void submitReceipt() {
Thread thread = new Thread(null, submitReceiptRunnable);
thread.start();
progressDialog = ProgressDialog.show(this, "Please wait...", "Publishing receipt ...", true);
}
private String getBase64Receipt() {
try {
InputStream inputStream = getContentResolver().openInputStream(imageCaptureUri);
byte[] bytes = CommonUtil.getBytesFromInputStream(inputStream);
return Base64.encodeBytes(bytes);
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
}
return null;
}
private void publishReceipt() {
String receipt = getBase64Receipt();
...
}
}
Are you sure that image crop mode forcing
intent.putExtra("return-data", true);
works correctly for the device you use. Correct me if I am wrong, but it is not safe and not well documented approach. Here you can find example of working code without cropping.
UPDATE: Issue you are facing with has long history, also at SO:
https://stackoverflow.com/questions/3904685/unable-to-find-com-android-camera-cropimage-activity-in-android
Issue I experienced was using crop immediatelly after image was taken by the camera. Also, it is not compatible through different Android versions, so if you get it working for 1.5 maybe it will not work for 2.3. Definitely something is wrong, as may be concluded from the Android Developer Group posts:
http://groups.google.com/group/android-developers/browse_thread/thread/2dd647523926192c/569f36b5b28f2661?lnk=gst&q=Crop+image+intent#569f36b5b28f2661
http://groups.google.com/group/android-developers/browse_thread/thread/2dd647523926192c/dcbe5aef29eddad6?lnk=gst&q=Crop+image+intent#dcbe5aef29eddad6
http://groups.google.com/group/android-developers/browse_thread/thread/d7b6a133c164aa17/184bf3b85da2ce58?lnk=gst&q=Crop+image+intent#184bf3b85da2ce58
Related
I have targeted Android API level 30 and tried to create multiple file descriptors for a single file from the URI from the default file picker which looks like this.
content://com.android.externalstorage.documents/document/E8A6-89C4%3AMovies%2FTestFile.mp4
content://com.android.externalstorage.documents/document/primary%3ATestFile.mp4
I am using the below code to create 10 threads to asynchronously access a file with ParcelFileDescriptors.
public class TestActivity extends AppCompatActivity {
public static final String TAG = "TEST_LOG";
private Button pickFileBtn;
final int VIDEO_REQUEST_CODE = 111;
#Override
public void onCreate(#Nullable Bundle savedInstanceState, #Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.test_activity);
pickFileBtn = findViewById(R.id.pick_file);
pickFileBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pickFile();
}
});
}
private void pickFile() {
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, VIDEO_REQUEST_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == VIDEO_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
loadFrame(data.getData());
}
}
}
void loadFrame(Uri uri) {
for (int i = 0; i < 10; i++) {
new Thread(new CustomRunnable(uri)).start();
}
}
}
class CustomRunnable implements Runnable {
private Uri uri;
public CustomRunnable(Uri uri) {
this.uri = uri;
}
#Override
public void run() {
try {
ParcelFileDescriptor descriptor = null;
try {
descriptor = CustomApplication.appContext.getContentResolver().openFileDescriptor(uri, "r");
// Working with the descriptor here.
} catch (Exception e) {
Log.e(TestActivity.TAG, String.format("Failed to obtain parcelFileDescriptor for %s.%s", uri.toString(), e.getMessage()));
} finally {
if (descriptor != null)
descriptor.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Failed to obtain r parcelFileDescriptor for content://com.android.externalstorage.documents/document/primary%3ATestFile.mp4.Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/document/primary%3ATestFile.mp4 from pid=6190, uid=12283 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
This can create around 5 descriptors and throws File Not Found Exception for the rest. But, It can successfully create all the required descriptors when I use URI from the media store. And the media store URI looks like this.
content://media/external/video/media/268019
I have tried to reuse the 5 descriptors but when I try to read the files using them, I get an error saying EBML header parsing failed
I have also tried to obtain access to a specific folder using Intent.ACTION_OPEN_DOCUMENT_TREE and then picking a file, but the result is the same, that it only opens 5 descriptors.
Why do opening descriptors from the default file picker only create 5 descriptors and why I can not reuse them.
as the title says, I'm trying to scan 1D barcodes, so far I have thet following code:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void test(View view){
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.putExtra("SCAN_MODE", "1D_CODE_MODE");
startActivityForResult(intent, 0);
}
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case IntentIntegrator.REQUEST_CODE:
if (resultCode == Activity.RESULT_OK) {
IntentResult intentResult =
IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (intentResult != null) {
String contents = intentResult.getContents();
String format = intentResult.getFormatName();
TextView uno = (TextView) findViewById(R.id.textView1);
uno.setText(contents);
Toast.makeText(this, "Numero: " + contents, Toast.LENGTH_LONG).show();
Log.d("SEARCH_EAN", "OK, EAN: " + contents + ", FORMAT: " + format);
} else {
Log.e("SEARCH_EAN", "IntentResult je NULL!");
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Log.e("SEARCH_EAN", "CANCEL");
}
}
}
}
And of course, I have both IntentResult and IntentIntegrator added to the project.
So, the scanner is beeing called correctly when a button is pressed and it seems to scan the code perfectly (it says "Text found" after it scans it), but it seems that the onActivityResult is not called, since the TextView is not beeing updated and the Toast is not appearing.
Any idea on what the mistake could be?
Thanks in advance!
Your first mistake is not using IntentIntegrator.initiateScan(), replacing it with your own hand-rolled call to startActivityForResult().
Your second mistake is in assuming that IntentIntegrator.REQUEST_CODE is 0. It is not.
Hence, with your current code, you are sending out a request with request code of 0, which is coming back to onActivityResult() with request code of 0, which you are ignoring, because you are only looking for IntentIntegrator.REQUEST_CODE.
Simply replace the body of your test() method with a call to initiateScan(), and you should be in better shape. Here is a sample project that demonstrates the use of IntentIntegrator.
I resolve your same problem so.
public class MainActivity extends Activity {
private TextView tvStatus, tvResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.tvStatus = (TextView) findViewById(R.id.tvStatus);
this.tvResult = (TextView) findViewById(R.id.tvResult);
Button scanBtn = (Button) findViewById(R.id.btnScan);
scanBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
Intent intent = new Intent(
"com.google.zxing.client.android.SCAN");
intent.putExtra("SCAN_FORMATS", "QR_CODE_MODE");
startActivityForResult(intent,
IntentIntegrator.REQUEST_CODE);
} catch (Exception e) {
Log.e("BARCODE_ERROR", e.getMessage());
}
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(
requestCode, resultCode, intent);
if (scanResult != null) {
this.tvStatus.setText(scanResult.getContents());
this.tvResult.setText(scanResult.getFormatName());
}
}
}
The onActivityResault function must be overridden. just add an #Override before the function declaration and it will be solved.
I thought it was simple to capture camera image to a file, since there are many examples. But after tying a lot of them, I still not get it work.
My code is:
public class MyActivity extends Activity {
private Button btn;
private ImageView imageView;
private static final File photoPath = new File(Environment.getExternalStorageState(), "camera.jpg");
private static final int CAMERA = 1;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
setListeners();
}
private void setListeners() {
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoPath));
startActivityForResult(intent, CAMERA);
}
});
}
private void findViews() {
btn = (Button) findViewById(R.id.btn);
imageView = (ImageView) findViewById(R.id.imageView);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA) {
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = getCameraBitmap(data);
if (bitmap == null) {
Toast.makeText(MyActivity.this, "Can't get bitmap from camera", Toast.LENGTH_LONG).show();
} else {
imageView.setImageBitmap(bitmap);
}
} catch (IOException e) {
Toast.makeText(MyActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
}
}
}
public Bitmap getCameraBitmap(Intent data) throws IOException {
if (data == null) {
// try solution 1
try {
return MediaStore.Images.Media.getBitmap(getContentResolver(), Uri.fromFile(photoPath));
} catch (FileNotFoundException e) {
return BitmapFactory.decodeFile(photoPath.getAbsolutePath());
}
} else {
Uri image = data.getData();
if (image != null) {
// try solution 3
InputStream inputStream = getContentResolver().openInputStream(image);
return BitmapFactory.decodeStream(inputStream);
} else {
// try solution 4
return (Bitmap) data.getExtras().get("data");
}
}
}
}
But it still get "Can't get bitmap from camera" shown. I don't known where is wrong.
I also created a working demo: https://github.com/freewind/AndroidCameraTest, you can see the full code there, and you may clone it and have a try on your own android device :)
Update
This code is working fine on android emulators, but not on my android pad.
I have seen this problem too; I removed intent.putExtra(MediaStore.EXTRA_OUTPUT,...), and it worked using the method:
stream = getContentResolver().openInputStream(data.getData());
image = BitmapFactory.decodeStream(stream);
how to store the imagePath of the image that I had captured using the camera activity to database. I also need to retrieve that imagePath and display on another activity?
Can someone help me please?
Update:
public class Image_secondPage extends Activity
{
public static final int CAMERA_RESULT = 1;
Button btn1;
ImageView imageView1;
private final String tag = getClass().getName();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.image_secondpage);
imageView1 = (ImageView)findViewById(R.id.imageView1);
Button btnNext = (Button)findViewById(R.id.buttonNext);
btnNext.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Intent intent = new Intent(Image_secondPage.this, ImagesPage.class);
startActivity(intent);
}
});
PackageManager pm = getPackageManager();
if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA))
{
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, MyFileContentProvider.CONTENT_URI);
startActivityForResult(i, CAMERA_RESULT);
}
else
{
Toast.makeText(getBaseContext(), "Camera is not available", Toast.LENGTH_LONG).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
Log.i(tag, "Receive the camera result");
if(resultCode == RESULT_OK && requestCode == CAMERA_RESULT)
{
File out = new File(getFilesDir(), "newImage.jpg");
if(!out.exists())
{
Toast.makeText(getBaseContext(), "Error while capturing image", Toast.LENGTH_LONG).show();
return;
}
Bitmap mBitmap = BitmapFactory.decodeFile(out.getAbsolutePath());
imageView1.setImageBitmap(mBitmap);
}
}
#Override
protected void onDestroy()
{
super.onDestroy();
imageView1 = null;
}
I am supposed to get the imagePath that I have captured and show the image on the imageView that I had on the next class but I don't know how. Can someone help me?
try use this
bitmap = (Bitmap) data.getExtras().get("data");
this will give you bitmap image, then you can save it to database or anything you want.
let me know if this not solve your problem.
I have developed a camera application with default camera. This application works in all other Android phones but some problem with Samsung Galaxy S
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
This code is giving a result and I am getting a bitmap image. But I couldn't retrieve an image path from this.
When I give EXTRA_OUTPUT, Galaxy S returning a null value. So that I couldn't define file path and name before calling camera intent. When we take picture using this application, Galaxy S is saving this picture in default location and not saving to pre defined location.
If anybody has solution for this, please help me.
What I've done for this is define a location for EXTRA_OUTPUT as a Uri, cache that in a static or member variable, and then in onActivity result use the cached location to retrieve the image. I had the same problem you were describing, and this seems to work fine. The only drawback is having 2 copies of the image, one in the location you defined in EXTRA_OUTPUT, and one in the default location.
Found answer here is the best example which is it self bothering about the device!
AndroidCameraUtils
- Download the project and from library project by including it below is the code snippet you can use !
private void setupCameraIntentHelper() {
mCameraIntentHelper = new CameraIntentHelper(this, new CameraIntentHelperCallback() {
#Override
public void onPhotoUriFound(Date dateCameraIntentStarted, Uri photoUri, int rotateXDegrees) {
messageView.setText(getString(R.string.activity_camera_intent_photo_uri_found) + photoUri.toString());
Bitmap photo = BitmapHelper.readBitmap(CameraIntentActivity.this, photoUri);
if (photo != null) {
photo = BitmapHelper.shrinkBitmap(photo, 300, rotateXDegrees);
ImageView imageView = (ImageView) findViewById(de.ecotastic.android.camerautil.sample.R.id.activity_camera_intent_image_view);
imageView.setImageBitmap(photo);
}
}
#Override
public void deletePhotoWithUri(Uri photoUri) {
BitmapHelper.deleteImageWithUriIfExists(photoUri, CameraIntentActivity.this);
}
#Override
public void onSdCardNotMounted() {
Toast.makeText(getApplicationContext(), getString(R.string.error_sd_card_not_mounted), Toast.LENGTH_LONG).show();
}
#Override
public void onCanceled() {
Toast.makeText(getApplicationContext(), getString(R.string.warning_camera_intent_canceled), Toast.LENGTH_LONG).show();
}
#Override
public void onCouldNotTakePhoto() {
Toast.makeText(getApplicationContext(), getString(R.string.error_could_not_take_photo), Toast.LENGTH_LONG).show();
}
#Override
public void onPhotoUriNotFound() {
messageView.setText(getString(R.string.activity_camera_intent_photo_uri_not_found));
}
#Override
public void logException(Exception e) {
Toast.makeText(getApplicationContext(), getString(R.string.error_sth_went_wrong), Toast.LENGTH_LONG).show();
Log.d(getClass().getName(), e.getMessage());
}
});
}
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
mCameraIntentHelper.onSaveInstanceState(savedInstanceState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mCameraIntentHelper.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
mCameraIntentHelper.onActivityResult(requestCode, resultCode, intent);
}
}
Add below lined to manifest file of your activityandroid:configChanges="keyboardHidden|orientation|screenSize"
NOTE:- I tried many examples for camera utils and ofcourse there are another ways to handle it but for beginners and person who are not too much familier with the core concepts would be more comfort with this project. THanks!