How can I limit a user to only picking photos from Android's MediaStore? - android

I want users to be able to choose a photo from their media library but don't want them to be able to choose a video. I'm having trouble limiting them to only choosing a photo. When I open the gallery app using
new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
then they are able to choose both photos and videos. Is there a way to limit them to only choosing photos?

For that you need to also set a mime type to "image/*" using Intent.setType(String type).
UPDATE: Looks like the proper way to set Uri and mime type at once is:
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
UPDATE 2: This is because when we set mime type or data uri separatelly look what happens (taken from Intent sources):
public Intent setType(String type) {
mData = null;
mType = type;
return this;
}
public Intent setData(Uri data) {
mData = data;
mType = null;
return this;
}
At least this is true on API 2.2.

Another option would be to use ACTION_GET_CONTENT instead of ACTION_PICK. It allows you to set a the MIME type you want without having to specify a URI at all.

Related

How can i send either an image or a video file using ACTION_SEND?

I want to share either an image or a video file using ACTION_SEND. So basically when the users taps on an image and selects "share image/video" it should send either the image selected or the video selected.
here is my code i am using:
if (filep != null) {
}
File sending=new File(filep);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_SEND);
intent.setDataAndType(Uri.fromFile(sending),getMimeType(sending.getAbsolutePath()));
intent.putExtra(Intent.EXTRA_STREAM, sending);
startActivity(Intent.createChooser(intent , "Share"));
}
private String getMimeType(String url)
{
String parts[]=url.split("\\.");
String extension=parts[parts.length-1];
String type = null;
if (extension != null) {
MimeTypeMap mime = MimeTypeMap.getSingleton();
type = mime.getMimeTypeFromExtension(extension);
}
return type;
So when testing, it takes me to which app i want to use to share with i.e whatsapp, Facebook, email etc. And then when selecting either one, it then says "sharing failed, please try again." I can't seem to figure out why it doesn't work. However i have the same code to display either image or video file full screen with ACTION_VIEW and that seems to work great but not with sharing.
Can anyone assist please?
EXTRA_STREAM needs to be a Uri, and you are not passing a Uri. Use Uri.fromFile() to construct a Uri.
Also, replace setDataAndType() with setType(), as ACTION_SEND does not use the data aspect of the Intent.

Android: Finding/choosing an intent that "shouldn't" be associated with a certain file?

I have an app that stores files in getExternalFilesDir(null)... for whatever reason (how other programmers coded their intent filter), not all the apps that I could normally open up for a file if it was in a less nested/non-dotted directory show up as options with this code:
intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(file);
try{
intent.setType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(uri.toString())));
intent.setData(uri);
Log.v(TAG, "Mime type="+MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(uri.toString())));
Log.v(TAG, "Uri="+uri.toString());
}catch(Exception e){
Log.v(TAG, "Uri="+uri.toString());
intent.setData(uri);
}
How can I get a listing of the available apps for a certain MIME type, and/or fudge the URI to get around the intent filter (but still pass in the true URI to the app), so I can make a dialog and my user can pick one? Or, is there a builtin way to do this and display the dialog?

Browse path on SD card via Intent

I'd like to know if there's a way to open a file browser (system or 3rd party like Astro) to a specific path. There's not much else to say here... pretty straight-forward question.
Sounds like ACTION_GET_CONTENT is what you want. See here. The relevant bits would be:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
startActivityForResult(intent,PICKFILE_RESULT_CODE);
On my phone (which has astro already installed), this brings up an astro dialog for /sdcard. I'm not sure what this will do on a phone with no file browser installed. I'm also unsure about whether you are able to actually specify the starting path using this method. The docs make it sound like you can't specify a starting uri for ACTION_GET_CONTENT.
EDIT: I think I understand the question better now. I thought you were wanting a picker style browser to just get a file path from the user. If you want a full blown browser to handle your uri, then this worked for me:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/Music"), "*/*");
startActivity(intent);
That will probably give you quite a long list of possible handlers, but I'd bet any file manager on the system would be in the list (astro certainly is).
I don't believe that any of the manufacturer provided File Browsers provide such a thing.
Though I don't see anything glaringly wrong with the theory of doing so. I imagine you are more likely to find a 3rd party file browser with this feature, but I've never come across any of those either.
You might look in to the Open Intents OI File Manager this concept seems right up their ally, if they don't already have this feature, I bet they might consider adding it if you get in contact with them.
Here i am going to show you that how to create a BROWSE button, which when you will click, it will open up the SDCARD, you will select a File and in result you will get the File Name and File path of the selected one:
// A button which you will hit**
browse.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
Uri startDir = Uri.fromFile(new File("/sdcard"));
startActivityForResult(intent, PICK_REQUEST_CODE);
}
});
//The function which will get the Resulted File Name and File Path
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if (requestCode == PICK_REQUEST_CODE)
{
if (resultCode == RESULT_OK)
{
Uri uri = intent.getData();
if (uri.getScheme().toString().compareTo("content")==0)
{
Cursor cursor =getContentResolver().query(uri, null, null, null, null);
if (cursor.moveToFirst())
{
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
Uri filePathUri = Uri.parse(cursor.getString(column_index));
String file_name = filePathUri.getLastPathSegment().toString();
String file_path=filePathUri.getPath();
Toast.makeText(this,"File Name & PATH are:"+file_name+"\n"+file_path, Toast.LENGTH_LONG).show();
}
}
}
}
}

How do I determine if Android can handle PDF

I know Android cannot handle PDFs natively. However, the Nexus One (and possibly other phones) come pre-installed with QuickOffice Viewer. How would I determine whether the user has a PDF viewer installed?
Currently, the code to start the PDF download looks pretty simple:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
After the download, the user clicks on the downloaded file to invoke the viewer.
However, if there is no PDF viewer, Android reports "Cannot download. The content is not supported on the phone."
I want to determine if the user will get this message, and if so, direct them to PDF apps in the Android Market.
I have been testing this and found that the following works. First you download the file independently and store it on the device and then you go do this:
File file = new File("/sdcard/download/somepdf.pdf");
PackageManager packageManager = getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType("application/pdf");
List list = packageManager.queryIntentActivities(testIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0 && file.isFile()) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
I have tested this on various emulator and a rooted cyanogen phone as well as a HTC Magic. If no pdf renderer is available the list will return zero and nothing will happen.
It seems to be important to set the data type to the pdf mime type to get the correct behaviour.
If you e.g. install droidreader it will react to the intent and display the pdf.
Of course you could do the check before you download the pdf as well depending on your use case or do things like popping up alerts or redirecting do other intents for download or whatever.
Edit: I have since refactored this out into a separate method ..
public static final String MIME_TYPE_PDF = "application/pdf";
/**
* Check if the supplied context can render PDF files via some installed application that reacts to a intent
* with the pdf mime type and viewing action.
*
* #param context
* #return
*/
public static boolean canDisplayPdf(Context context) {
PackageManager packageManager = context.getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType(MIME_TYPE_PDF);
if (packageManager.queryIntentActivities(testIntent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0) {
return true;
} else {
return false;
}
}
You can query the PackageManager to see if there's a package that can handle your Intent. Here's an example: http://www.curious-creature.org/2008/12/15/android-can-i-use-this-intent/
You will probably use asynch task to download any file.so simple way is Just add below code in post execute() method of asynch task.it will ask for choice.
FileOpener.open(context, file);
and file should contain info about filepath and filename.Example
File file = new File(Environment
.getExternalStoragePublicDirectory("/MDroid")
+ filepath + fileName );
Hope it helps

Single intent to let user take picture OR pick image from gallery in Android

I'm developing an app for Android 2.1 upwards. I want to enable my users to select a profile picture within my app (I'm not using the contacts framework).
The ideal solution would be to fire an intent that enables the user to select an image from the gallery, but if an appropriate image is not available then use the camera to take a picture (or vice-versa i.e. allow user to take picture but if they know they already have a suitable image already, let them drop into the gallery and pick said image).
Currently I can do one or the other but not both.
If I go directly into camera mode using MediaStore.ACTION_IMAGE_CAPTURE then there is no option to drop into the gallery.
If I go directly to the gallery using Intent.ACTION_PICK then I can pick an image but if I click the camera button (in top right hand corner of gallery) then a new camera intent is fired. So, any picture that is taken is not returned directly to my application. (Sure you can press the back button to drop back into the gallery and select image from there but this is an extra unnecessary step and is not at all intuitive).
So is there a way to combine both or am I going to have to offer a menu to do one or the other from within my application? Seems like it would be a common use case...surely I'm missing something?
You can try doing something like this:
// ...
// Within your enclosing Class
// ...
private static final int SELECT_PICTURE = 1;
// ...
Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String pickTitle = "Select or take a new Picture"; // Or get from strings.xml
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
chooserIntent.putExtra
(
Intent.EXTRA_INITIAL_INTENTS,
new Intent[] { takePhotoIntent }
);
startActivityForResult(chooserIntent, SELECT_PICTURE);
To see how to handle the activitiy's result, please refer to this question
Note: a critical point is how to determine whether the camera or gallery was used. That is shown in this code example: https://stackoverflow.com/a/12347567/294884
UPDATE: The other answer, using EXTRA_INITIAL_INTENTS, is a better one at this point. At the time I wrote my answer, EXTRA_INITIAL_INTENTS did not yet exist, as it was added in API Level 5.
So is there a way to combine both or
am I going to have to offer a menu to
do one or the other from within my
application?
Write your own gallery that has the features you desire.
I would think a menu would be simpler.
Seems like it would be a common use
case...surely I'm missing something?
The developer next to you will think the gallery should allow you to pick from the local gallery or else hop out to Flickr to make a selection from there. Another developer will think the camera should not only allow to "take a picture" via the camera but to "take a picture" via choosing something from the gallery, inverting things from the way you envision it. Yet another developer will think that the gallery should allow picking from the local gallery, or Flickr, or the camera, or a network-attached webcam. Still another developer will think that the gallery is stupid and users should just pick files via a file explorer. And so on.
All of this in an environment (mobile phones) where flash for the OS is at a premium.
Hence, IMHO, it is not completely shocking that the core Android team elected to provide building blocks for you to assemble as you see fit, rather than trying to accommodate every possible pattern.
You can proceed in this way in your Activity:
private static final int REQUEST_CODE_PICTURE= 1;
/**
* Click on View to change photo. Sets into View of your layout, android:onClick="clickOnPhoto"
* #param view View
*/
public void clickOnPhoto(View view) {
Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String pickTitle = "Take or select a photo";
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { takePhotoIntent });
startActivityForResult(chooserIntent, REQUEST_CODE_PICTURE);
}
Then, add always in your Activity the method onActivityResult:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_PICTURE && resultCode == Activity.RESULT_OK) {
if (data == null) {
return;
}
try {
InputStream inputStream = getContentResolver().openInputStream(data.getData());
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
imgPhoto.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
My Answer is almost identical to #Macarse solution but I also add an additional intent to show gallery apps (Ex: Google Photos) and is written in Kotlin:
val REQUEST_CODE_GET_IMAGE = 101
private fun addProfileImage() {
val pickImageFileIntent = Intent()
pickImageFileIntent.type = "image/*"
pickImageFileIntent.action = Intent.ACTION_GET_CONTENT
val pickGalleryImageIntent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
val captureCameraImageIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val pickTitle = "Capture from camera or Select from gallery the Profile photo"
val chooserIntent = Intent.createChooser(pickImageFileIntent, pickTitle)
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(captureCameraImageIntent, pickGalleryImageIntent))
startActivityForResult(chooserIntent, REQUEST_CODE_GET_IMAGE)
}
Extract image from result intent:
private var imageTempFile: File? = null
private var imageMimeType: String? = null
private fun extractImage(intent: Intent?) {
val imageUri = intent?.data
imageUri?.let {
Glide.with(this)
.load(imageUri)
.into(profileImageCiv)
imageTempFile = MediaUtils.copyContentFromUriToCacheFile(this, imageUri, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
imageMimeType = MediaUtils.getMimeType(this, imageUri)
} ?: run {
intent?.extras?.get("data")?.let { bitmap -> // Bitmap was returned as raw bitmap
Glide.with(this)
.load(bitmap)
.into(profileImageCiv)
imageTempFile = MediaUtils.writeBitmapToCacheFile(this, bitmap as Bitmap, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
imageMimeType = "image/jpeg" // The bitmap was compressed as JPEG format. The bitmap itself doesn't have any format associated to it
} ?: run {
imageTempFile = null
imageMimeType = null
Log.e("Intent data is null.")
Log.d("Error during photo selection")
}
}
}

Categories

Resources