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
Related
I am trying to create a personal chatting app which has a button. When click of that button the frame becomes visible which have buttons on click chooser is been created like this. When the image button is clicked it creates the chooser activity after selecting the file I have saved it in imagefile Uri.
But when I try to get the path of the file by using the data.getdata().getpath() method it gives doument/236 as the output but didn't give the actual path of the file. When I try to use fileutlis to get the path then it says "can't resolve fileutils". Please help me so that I can get the path of my file.
imagesend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
checker = "image";
Intent imageIntent = new Intent();
imageIntent.setAction(Intent.ACTION_GET_CONTENT);
imageIntent.setType("image/*");
startActivityForResult(Intent.createChooser(imageIntent,"Select Image"),438);
}
});
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 438 && resultCode == RESULT_OK && data!=null && data.getData()!=null){
loadingBar.setTitle("Sending Message");
loadingBar.setMessage("Please wait...");
loadingBar.setCanceledOnTouchOutside(false);
loadingBar.show();
imagefile = data.getData();
String filepath = data.getData().getPath();
if(checker.equals("pdf")){
pdfFilemessage();
}else if(checker.equals("image")){
//imagefilemessage();
Toast.makeText(personalChat.this,filepath,Toast.LENGTH_SHORT).show();
}
}
}
This line returns the Uri of the file.
imagefile = data.getData();
What you have to do is,
public String getRealPathFromURI(Uri contentUri) {
String[] proj = {
MediaStore.Audio.Media.DATA
};
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
Add this to your code.
String filePath = this.getRealPathFromURI(imagefile);
Refer this: https://stackoverflow.com/a/13209514
You can try this:
Uri fileUri = intent.getData();
Now from this you can use the below gist file to generate the file path from the URI
https://gist.github.com/tatocaster/32aad15f6e0c50311626
With Android 10 you won't by default be able to access the file directly by path as Google are forcing people to use Storage Access Framework and or MediaStore to access files.
With Android 11 their plan is to make this the only way to access files.
See https://developer.android.com/training/data-storage/files/external-scoped for details.
You will need to use ContentResolver#openFileDescriptor(Uri, String)
and ParcelFileDescriptor#getFileDescriptor() to get something usable
e.g.
ParcelFileDescriptor pfd =
this.getContentResolver().
openFileDescriptor(Uri, "r");
FileInputStream fileInputStream =
new FileInputStream(
pfd.getFileDescriptor());
If you want to get other info about the file you can do that with a contentResolver Query on the URI for DISPLAY_NAME or MIME_TYPE for type of file.
e.g.
// useful name to display to user
Cursor cursor = this.getContentResolver()
.query(Uri, new String[] { MediaStore.Files.FileColumns.DISPLAY_NAME},
null, null, null);
cursor.moveToFirst();
filename = cursor.getString(0);
cursor.close();
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.
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
Can any ony give me guidelines on how to find the directory my Android device stores its images takem from a camera;
In the following code snippet, I intend to get a list of files in prior to launching the camera app. When returning from the camera app get a list of all the files in the same directory and process the newly added ones.
public void onBtnTakePhoto(final View view) {
existingfiles = UploadImageService.getFiles(<IMAGE_LOCATION>);
final Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
startActivityForResult(intent, TAKE_PICTURE);
}
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PICTURE:
List<String> newFies = UploadImageService.getFiles(<IMAGE_LOCATION>);
newFies.removeAll(existingfiles);
for (String newFile : newFies) {
File file = new File(newFile);
addImage( Uri.fromFile(file), PictureSource.CAMERA);
}
break;
}
// regardless of which activity, check that files exist:
verifyFilesExist(images);
}
As far as I understand it, you actually would have to launch your intent with the ACTION_IMAGE_CAPTURE action (instead of INTENT_ACTION_STILL_IMAGE_CAMERA). Then, in onActivityResult you have to get the data from the Intent: there you will find the reference to the image.
Look at the examples given here.
But as I look at your answer, you probably would find this more useful:
String[] projection = {
MediaStore.Images.ImageColumns._ID, MediaStore.Images.ImageColumns.DATA
};
String selection = "";
String[] selectionArgs = null;
mImageExternalCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null);
mImageInternalCursor =
managedQuery(MediaStore.Images.Media.INTERNAL_CONTENT_URI, projection,
selection, selectionArgs, null);
then
String filePath =
mImageExternalCursor.getString(mImageExternalCursor.getColumnIndexOrThrow(
MediaStore.Images.ImageColumns.DATA));
(since you don't actually want to take a new picture).
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.