In my costum camera app I need to transfer a bitmap and a Uri from one activity to another. For some reason I'm getting the FAILED BINDER TRANSACTION error on most phones(I get the error on newer phones but don't on Nexus4 and Galaxy3). I get the same error even when I only try to transfer the Bitmap through an intent(I also tried transfering only the Uri and got the error). From what I've read online the error comes from a memory problem but I don't know how to fix it. I would appreciate any kind of help.
My first Activity:
...
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
tv.setVisibility(View.INVISIBLE);
btn.setVisibility(View.INVISIBLE);
selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
System.out.println("Image Path : " + selectedImagePath);
img.setImageURI(selectedImageUri);
ok.setVisibility(View.VISIBLE);
}
}
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()==btn.getId())
{
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE);
}
if(v.getId()==ok.getId())
{
String stringUri;
stringUri = selectedImageUri.toString();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent .setClass(MainActivity.this, SecondMain.class);
intent .putExtra("KEY", stringUri);
startActivity(intent );
}
}
}
Second Activity:
public static Camera isCameraAvailiable(){
Camera object = null;
try {
object = Camera.open();// attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return object; // returns null if camera is unavailable
}
private Camera.PictureCallback capturedIt = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if(bitmap==null){
Toast.makeText(getApplicationContext(), "not taken", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(getApplicationContext(), "taken", Toast.LENGTH_SHORT).show();
}
cameraObject.release();
}
};
...
String stringUri = null;
Bundle extras = getIntent().getExtras();
if (extras != null && extras.containsKey("KEY")) {
stringUri= extras.getString("KEY");
}
selectedImageUri = Uri.parse(extras.getString("KEY"));
float alpha=(float)1/2;
img.setAlpha(alpha);
img.setImageURI(selectedImageUri);
cameraObject = isCameraAvailiable();
showCamera = new ShowCamera(this, cameraObject);
frame.addView(showCamera);
}
public void snapIt(View view){
redo.setVisibility(View.VISIBLE);
ok.setVisibility(View.VISIBLE);
snap.setVisibility(View.INVISIBLE);
cameraObject.takePicture(null, null, capturedIt);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()==ok.getId())
{
Intent intent = new Intent(SecondMain.this, Blend.class);
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[]byteArray=stream.toByteArray();
intent.putExtra("image", byteArray);
String stringUri;
stringUri = selectedImageUri.toString();
intent .putExtra("KEY", stringUri);
startActivity(intent);
It is not a memory problem, it's a problem with transferring your image with your intent. You see, Bundle has a limit of how much data it can transfer from one end to the other, currently it's only 1MB. You will problems on all modern phones with a decent camera, as the image exceeds 1MB limit, some old phones with low end camera will work. You need to rethink on how you are going to be transfering the image.
You can
Save it to a file first, send the only the path to it (that's how selecting an image from the gallery works)
Save it to SQL and retrive it on the other end
Make a hodler class with a static variable of image (the most simple)
Make a custom class of Application and put it there for the time being.
Downscale and compress the image before it's transferred
Related
I created a button that lets the user choose between "Take picture with camera" and "Select picture from gallery".
When the picture is taken/chosen, I then display it in an ImageView of the next activity which I do by passing the URI of the file created to store the taken/selected picture.
It works as expected when the user takes a picture with his camera but when he selects an image from gallery, no image is shown in the next activity despite both intents (take a picture and select a picture) being coded the same.
My question(s): Why isn't the image displayed in the next activity ONLY when picked from the gallery ? Or how should I proceed to display it ?
Intent to open camera (working fine):
private void openCameraToTakePictureIntent() {
Log.d(TAG, "Method for Intent Camera started");
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.emergence.pantherapp.fileprovider", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
Intent to access gallery and pick an image:
private void openGalleryIntent() {
Log.d(TAG, "Method for Intent Gallery started");
Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
if (galleryIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.emergence.pantherapp.fileprovider", photoFile);
galleryIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(galleryIntent, PICK_IMAGE);
}
}
}
Then here's the onActivityResult: (currentPhotoPath is the absolute path of the file created to store the image)
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && requestCode == 1) {
Log.d(TAG, currentPhotoPath);
Intent intent = new Intent(this, ModifyPictureActivity.class);
intent.putExtra("USER_IMAGE", currentPhotoPath);
startActivity(intent);
} else if (resultCode == Activity.RESULT_OK && requestCode == 2) {
Log.d(TAG, currentPhotoPath);
Intent intent = new Intent(this, ModifyPictureActivity.class);
intent.putExtra("USER_IMAGE", currentPhotoPath);
startActivity(intent);
}
}
Below is how the image is displayed in the following activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_modify_picture);
Intent intent = getIntent();
String imageUri = intent.getStringExtra("USER_IMAGE");
if (imageUri != null) {
Log.d(TAG, imageUri);
} else {
Log.d(TAG, "imageUri was null");
}
image = findViewById(R.id.picture);
image.setImageURI(Uri.parse(imageUri));
}
I made sure to have the READ_EXTERNAL_STORAGE in the manifest and the xml layout is just set to "match_parent" for height and width but I can add them if it's relevant.
Few Intent actions use EXTRA_OUTPUT. Mostly, that is an ACTION_IMAGE_CAPTURE thing.
More typically, an Intent for getting a piece of content (ACTION_PICK, ACTION_GET_CONTENT, ACTION_OPEN_DOCUMENT, ACTION_CREATE_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE, etc.) return a Uri from the content supplier in the Intentdelivered toonActivityResult(). Given your implementation, that would be data.getData()to get thatUri`.
You can then use a ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri. In your case, for example, you could use that InputStream to copy the bytes to a FileOutputStream to make your own local copy of the content.
Note that you only have short-term access to the content identified by the Uri.
OK, so here is what I want to do in this android activity:
Press the button that says "choose pic"
Use intent or whatever, and go to choose a pic from your local photo library
Once you have chosen the pic, go to this activity
And this time, the image view below would be set (it will be the picture you've chosen)
I have read this q&a and tried the code below, in the activity, but it didnt work out.
android pick images from gallery
*for the last line I couldn't figure out what to write, I just wanted to set the exact picture
public void choosepic (View v){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickIntent.setType("image/*");
Intent chooserIntent = Intent.createChooser(getIntent, "Select Image");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {pickIntent});
startActivityForResult(chooserIntent, PICK_IMAGE);
foodpic.setpic
}
As your code says image cannot be set from the method where you launch the intent.
Override method with name onActivityResult() and use the following code in that method
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE && resultCode == RESULT_OK && data != null) {
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
// String picturePath contains the path of selected Image
ImageView imageView = (ImageView) findViewById(R.id.imgView);
Bitmap bmp = null;
try {
bmp = getBitmapFromUri(selectedImage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
imageView.setImageBitmap(bmp);
}
Hope this helps.
For instance, when I want to attach an image to a text message in the stock Messages app, I get a familiar system dialog presenting the Camera, Gallery, and other image Content Providers.
I want to use this in my own app. I see plenty of libraries that allow the user to choose between Gallery and Camera, but I want all of the user's installed Image source to appear.
Is the system dialog from Messages (and other stock apps, such as Mail) really custom for those apps? Do we really need to build our own? Storage Access Framework does not appear to be the right solution since it bypasses the camera (or other image sources that I haven't thought of but may be present on a user's device).
I would suggest Intent.ACTION_PICK
private void selectFileFromGallery() {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), requestGallery);
}
It will open a dialog like this that contains all of users app that can be used as an image picker :
And then when user chosses image:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == requestGallery) {
onSelectFromGalleryResult(data);
}
}
#SuppressWarnings("deprecation")
private void onSelectFromGalleryResult(Intent data) {
Uri uri = data.getData();
if (!uri.toString().contains("file")) {
if (uri.toString().contains("external")) {//chosen from external storage
photoUri = Uri.parse("file://" + getRealPathFromURI(uri));
} else {
photoUri = Uri.parse("file://" + (Build.VERSION.SDK_INT <= 18
? getRealPathFromURI_API11to18(getActivity(), uri) :
getRealPathFromURI_API19(getActivity(), uri)));
}
}
#SuppressLint("NewApi")
private String getRealPathFromURI_API19(Context context, Uri uri) {
return RealPathUtil.INSTANCE.getRealPathFromURI_API19(context, uri);
}
public String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getActivity().managedQuery(contentUri, proj, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
#SuppressLint("NewApi")
private String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
contentUri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
if (cursor != null) {
int column_index =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
}
return result;
}
The thing you are asking for can be done using System Access Frame work.
Add Storage Permissions inside the manifest file, and then check if the permission is accepted or not. Then you can open open document choose to let the user choose the image.
Code
Inside some onClick
Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(i, 41);
This will open file chooser activity for image files only.
Then you can get back the results inside:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK){
if (requestCode == 41) {
if (data != null) {
Uri uri = data.getData();
//This is the uri to the file
//To get the file use the uri
}
}
}
}
Still you have to create the BottomSheetDialog on your own, but your job will be drastically reduced as there will be only 2 options : 1. Camera app ,2. File chooser. You will have to handle the camera event on your own and get the image uri.
I suggest using android image Android-Image-Cropper by ArthurHub
It gives you all the options you are looking for
I'm creating a simple app to take a picture. this is my code
Button b1;
ImageView iv;
String TAG = "MAIN ACTIVITY";
File photo;
private Uri mImageUri;
private File createTemporaryFile(String part, String ext) throws Exception {
File externalStorageDirectory = Environment.getExternalStorageDirectory();
File tempDir = new File(externalStorageDirectory + "/cameratest/");
if (!tempDir.exists()) {
tempDir.mkdir();
}
return File.createTempFile(part, ext, tempDir);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b1 = (Button) findViewById(R.id.button);
iv = (ImageView) findViewById(R.id.imageView);
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
try {
// place where to store camera taken picture
photo = createTemporaryFile("picture", ".jpg");
photo.delete();
} catch (Exception e) {
Log.v(TAG, "Can't create file to take picture!");
Toast.makeText(getApplicationContext(), "Please check SD card! Image shot is impossible!",
Toast.LENGTH_SHORT).show();
}
mImageUri = Uri.fromFile(photo);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
startActivityForResult(intent, 0);
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == RESULT_OK) {
Log.d(TAG, mImageUri.toString());
Bitmap bitmap = BitmapFactory.decodeFile(mImageUri.toString());
iv.setImageBitmap(bitmap);
}
}
as you can see i've added eLog.d(TAG, mImageUri.toString()); at the end and in the logcat (as well as the FileNotFoundException) i see this direcory:
03-27 00:43:30.498 30526-30526/myapplication.example.falcoleo.cameratest1 D/MAINÂ ACTIVITY: file:///storage/emulated/0/cameratest/picture459838058.jpg
03-27 00:43:30.499 30526-30526/myapplication.example.falcoleo.cameratest1 E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: file:/storage/emulated/0/cameratest/picture459838058.jpg: open failed: ENOENT (No such file or directory)
guess if this directory exists?
spoler alert, it does. And it's not like the image is created after the BitmapFactory.decodeFile. I really do not understand what i'm doing wrong. Everything works fine except when it actually has to display the photo, then it just does not display it. just blank. Like WTF m8 i'm just trying to do my job no need to go crazy, you know.
Replace mImageUri.toString() with mImageUri.getPath().
decodeFile expects a path, not an uri string.
file:///storage/emulated/0/cameratest/picture459838058.jpg
Remove file:// because the decodeFile() expects a file system path.
/storage/emulated/0/cameratest/picture459838058.jpg
Use BitmapFactory.decodeStream instead of BitmapFactory.decodeFile.
try ( InputStream is = new URL( file_url ).openStream() ) {
Bitmap bitmap = BitmapFactory.decodeStream( is );
}
Source https://stackoverflow.com/a/28395036/5714364
Ok for me it was the file path was wrong so I needed to get the real filepath.
First
File file = new File(getPath(uri));
public String getPath (Uri uri)
{
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri,
projection,
null,
null,
null);
if (cursor == null)
return null;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String s = cursor.getString(column_index);
cursor.close();
return s;
}
Then Back To Uri
Uri newUri = Uri.fromFile(file);
This conversion to file and back to uri did the trick for me. I was receiving simple data from action.SEND.
I am new to Android. I have just created an AVD with 256 MB android-SDcard in it in Android 2.1. And I have inserted two images into it. I have done this using the DDMS perspective. And the images are now stored into a folder 100ANDRO in the DCIM folder of SDcard. Now I want to create an application that allows the user to select the images through browsing the folders and need to save the corresponding image to the database android-sqlite.
Can someone help me to find an appropriate method for this? Thanks in advance.
I have found one method for this.
I have created a button for UPLOAD and on the click action I have set like this.
upload.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, 1);
}
});
And I have overrided this method along with the same class as below.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1:
{
if (resultCode == RESULT_OK)
{
Uri photoUri = data.getData();
if (photoUri != null)
{
try {
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(photoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
imgView.setImageBitmap(bitmap);
int size = bitmap.getWidth() * bitmap.getHeight();
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();}
String bb = out.toString();
byte[] x = out.toByteArray();
image_value.setTag(x);
image_value.setText(filePath);
}catch(Exception e)
{}
}
}
}
Here image_value represents a hidden text view in the xml file.
I have passed the value of the image location and bytes as text view's value and tag.
And later on I have saved this bytes into the database for later display. Its working fine.
Thanks to all.