I'm referencing this link for showing images from a specific path in internal storage. But its only working with ACTION_VIEW but when I use ACTION_PICK its not showing that same path instead its simply opening gallery. Is there any way to select a single image from that specific path after showing?
public class NewActivity extends AppCompatActivity{
private static final String file_path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/fun";
private File[] allFiles ;
private String imagepath ;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File folder = new File(file_path);
allFiles = folder.listFiles();
findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new SingleMediaScanner(NewActivity.this, allFiles[0]);
}
});
}
public class SingleMediaScanner implements MediaScannerConnection.MediaScannerConnectionClient {
private MediaScannerConnection mMs;
private File mFile;
public SingleMediaScanner(Context context, File f) {
mFile = f;
mMs = new MediaScannerConnection(context, this);
mMs.connect();
}
public void onMediaScannerConnected() {
mMs.scanFile(mFile.getAbsolutePath(), null);
}
public void onScanCompleted(String path, Uri uri) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setData(uri);
startActivityForResult(intent, 100);
mMs.disconnect();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==100 && resultCode==RESULT_OK){
try{
Uri selectedImageUri = data.getData();
String[] projection = {MediaStore.Images.Media.DATA};
//Cursor cursor_gallery = activity.managedQuery(selectedImageUri, projection, null, null, null);
Cursor cursor_gallery = getContentResolver().query(selectedImageUri, projection, null, null, null);
int column_index = 0;
if (cursor_gallery != null) {
column_index = cursor_gallery.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor_gallery.moveToFirst();
imagepath = cursor_gallery.getString(column_index);
cursor_gallery.close();
}
System.out.println("sammy_imagepath "+imagepath);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
When you make an ACTION_PICK intent, you're asking another application to perform an action (let them pick a file). There is no way to ensure it works a certain way- the user could just as easily have added another app that implements ACTION_PICK and does something else. So no, there is no way to ensure it will pick from that path. If you absolutely need that, you need to implement your own picker instead of using ACTION_PICK.
Related
i would like to know the community opinion on the problem of getting image on Android from common sources to use in our App.
I know that there are questions back to 2010's about it on stack overflow, but i found the answers a bit to much boilerplate code for this simple task.
Maybe anyone knows some lightweight library to get image from gallery (or other common sources) so code can stay simple and readable
maybe something like:
Bitmap image;
SomeCoolLib.
.performImageSelect()
.asBitmap()
.listener(new RequestListener<String, Bitmap>() {
#Override
public boolean onException(Exception e) {
e.printStackTrace();
return false;
}
#Override
public boolean onCancel() {
return false;
}
}).into(image);
to let user:
The best way is to use the Android Storage Access Framework (https://developer.android.com/guide/topics/providers/document-provider.html).
For instance, in your activity you can request to the device and type of document (notice the intent.setType method, if you want to filter by document type).
This code will open the android document picker and let user to pick an image:
public class MainActivity extends AppCompatActivity {
private static final int OPEN_DOCUMENT_CODE = 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.floatingActionButton).setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, OPEN_DOCUMENT_CODE);
});
}
}
Then, just implement the onActivityResult in the very same activity, in order to receive the image selected:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (requestCode == OPEN_DOCUMENT_CODE && resultCode == RESULT_OK) {
if (resultData != null) {
// this is the image selected by the user
Uri imageUri = resultData.getData();
}
}
}
1, Pick a image
If u use this(Old style):
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
Or this(Official recommendation):
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
Those code will open FileManager in Android 8, that's difficult to use.
If u want to open the albums app in user's device and pick a photo, u should use this(I recommendation):
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
All those way before will get an Uri in onActivityResult(int, int, Intent).
2, Handle the Uri
Sometimes we need the image's real path, u should use those code:
#Nullable
public static String getImagePathFromUri(#Nullable Uri aUri) {
String imagePath = null;
if (aUri == null) {
return imagePath;
}
if (DocumentsContract.isDocumentUri(ApplicationContext.get(), aUri)) {
String documentId = DocumentsContract.getDocumentId(aUri);
if ("com.android.providers.media.documents".equals(aUri.getAuthority())) {
String id = documentId.split(":")[1];
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
} else if ("com.android.providers.downloads.documents".equals(aUri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
Long.valueOf(documentId));
imagePath = getImagePath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(aUri.getScheme())) {
imagePath = MediaUtils.getImagePath(aUri, null);
} else if ("file".equalsIgnoreCase(aUri.getScheme())) {
imagePath = aUri.getPath();
}
return imagePath;
}
private static String getImagePath(Uri aUri, String aSelection) {
String path = null;
Cursor cursor = ApplicationContext.get()
.getContentResolver()
.query(aUri, null, aSelection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
I used Intent ACTION_GET_CONTENT to show recent files from phone memory. That includes images, pdf, google drive documents(pdf, xlsx) as shown in screenshot below. I want to get the name and full path so that I can upload the file to server. I/m getting the mime type correctly as of now.
public class MainActivity extends AppCompatActivity {
Button btn;
TextView txt;
private final static int EXTERNAL = 111;
private final static int ATTACH = 11;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.btn);
txt = (TextView)findViewById(R.id.txt);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
photoIntent();
} else {
if (shouldShowRequestPermissionRationale(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// showToast("Permission Required...");
}
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL);
}
} else {
photoIntent();
}
}
});
}
private void photoIntent() {
Intent intent = new Intent();
Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath());
intent.setDataAndType(uri, "*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Complete action using"), ATTACH);
}
#Override
public void onRequestPermissionsResult(int requestcode, String[] permission, int[] grantRes){
if (requestcode == EXTERNAL) {
if (grantRes[0] == PackageManager.PERMISSION_GRANTED) {
photoIntent();
} else {
Toast.makeText(this, "Unable to Access Image", Toast.LENGTH_SHORT).show();
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ATTACH && resultCode == RESULT_OK){
Uri uri = data.getData();
System.out.println("sammy_sourceUri "+uri);
String mimeType = getContentResolver().getType(uri);
System.out.println("sammy_mimeType "+ mimeType);
}
}
}
I want to get the name and full path so that I can upload the file to server
There is no "full path", because there may not be a "file".
You are invoking ACTION_GET_CONTENT. This returns a Uri to some content. Where that content comes from is up to the developers of the ACTION_GET_CONTENT activity that the user chose. That could be:
An ordinary file on the filesystem that happens to be one that you could access
An ordinary file on the filesystem that resides somewhere that you cannot access, such as internal storage for the other app
A file that requires some sort of conversion for it to be useful, such as decryption
A BLOB column in a database
Content that is generated on the fly, the way this Web page is generated on the fly by the Stack Overflow servers
And so on
To use the content from the Uri, use a ContentResolver and openInputStream().
how to use this InputStream to upload to server API as file?
Either your chosen HTTP API supports an InputStream as the source of this content, or it does not. If it does, just use the InputStream directly. If not, use the InputStream to make a temporary copy of the content as a file that you can directly access (e.g., in getCacheDir()), upload that file, then delete the file when the upload is complete.
try this
public static ArrayList<String> getImagesFromCameraDir(Context context) {
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ArrayList<String> filePaths = new ArrayList<>();
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_ADDED};
Cursor mCursor = context.getContentResolver().query(mImageUri, columns, MediaStore.Images.Media.DATA + " like ? ", new String[]{"%/DCIM/%"}, null);
if (mCursor != null) {
mCursor.moveToFirst();
try {
int uploadImage = 0;
uploadImage = mCursor.getCount();
for (int index = 0; index < uploadImage; index++) {
mCursor.moveToPosition(index);
int idx = mCursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
filePaths.add(mCursor.getString(idx));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
mCursor.close();
}
}
return filePaths;
}
get real path from URI
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);
}
FILENAME :
String filename = path.substring(path.lastIndexOf("/")+1);
I have an activity A. Starting an activity B from A. In activity B, I capture an image with camera present in the device and at the end of that activity come back to Activity A. In this activity have to display the captured image. How to accomplish this task? Running on version 2.3.3...Have had a look here Capture Image from Camera and Display in Activity but the same NullPointerException...Running on LG device.
You can pass the URL of the captured image from Activity B to Activity A using intent.putExtras methos.
Refer Passing string array between android activities
For Capturing image refer below code
public class Camera extends Activity
{
private static final int CAMERA_REQUEST = 1888;
private String selectedImagePath;
WebView webview;
String fileName = "capturedImage.jpg";
private static Uri mCapturedImageURI;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
webview=(WebView)findViewById(R.id.webView1);
}
public void TakePhoto()
{
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
mCapturedImageURI = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent cameraIntent = new Intent(ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
if (requestCode == CAMERA_REQUEST)
{
selectedImagePath = getPath(mCapturedImageURI);
//Save the path to pass between activities
}
}
}
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);
}
}
I have to following code to launch and the audio recorder on Android:
final Intent recordSoundIntent = new Intent
("android.provider.MediaStore.RECORD_SOUND");
String fileName = Environment.getExternalStorageDirectory() +
File.separator + UUID.randomUUID() + ".3gpp";
recordSoundIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new
File(fileName)));
startActivityForResult(Intent.createChooser(recordSoundIntent,
getString(R.string.record_sound_chooser)), INTENT_SOUND_RECORDING);
My problem is the following:
My filename (fileName) has no effect, the Uri returned from
data.getData() returns in my last test run: content://media/external/audio/media/41.
However, this file is created on my sdcard: recording34485.3gpp. If it
is not possible to set custom location upon creating sound it is the
location to this file I would like.
Was working on the same problem. Could not find a way to set location directly but found a work around solution of getting and renaming it.
Getting file name was dealt with here, file is then renamed using java.io.File.renameTo(). You'll need android.permission.WRITE_EXTERNAL_STORAGE in your manifest file for the rename to work.
Here is my test code example:
public static final int REQUEST_RECORD_SOUND = 7;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
startActivityForResult(intent, REQUEST_RECORD_SOUND);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == REQUEST_RECORD_SOUND){
String sourcePath = getRealPathFromURI(intent.getData());
File root = Environment.getExternalStorageDirectory();
String destPath = root.getPath() + File.separator + "newName.txt";
File sourceF = new File(sourcePath);
try {
sourceF.renameTo(new File(destPath));
} catch (Exception e) {
Toast.makeText(this, "Error:" + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
/**
* from:
* https://stackoverflow.com/questions/3401579/get-filename-and-path-from-uri-from-mediastore
*/
public String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
I'm using following code to open a gallery inside of my app
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, FIND_RESULT);
Is it possible to limit a list of images to only show images taken by camera? Viewing Gallery on my 2.1 system, images are grouped so there has to be a parameter that defines to which folder it belongs.
Checking the MediaStore.Images.ImageColumns I did not a find any column that would define such thing.
Could I be wrong? Because if I could create a query to filter by folder and create my own gallery view, then my problem would be solved.
You just need to implement MediaScannerConnectionClient in your activity and after that you have to give the exact path of one of the file inside that folder name here as SCAN_PATH and it will scan all the files containing in that folder and open it inside built in gallery. So just give the name of you folder and you will get all the files inside including video. If you want to open only images change FILE_TYPE="image/*"
public class SlideShow extends Activity implements MediaScannerConnectionClient {
public String[] allFiles;
private String SCAN_PATH ;
private static final String FILE_TYPE = "*/*";
private MediaScannerConnection conn;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
File folder = new File("/sdcard/yourfoldername/");
allFiles = folder.list();
SCAN_PATH=Environment.getExternalStorageDirectory().toString()+"/yourfoldername/"+allFiles[0];
Button scanBtn = (Button) findViewById(R.id.scanBtn);
scanBtn.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
startScan();
}
});
}
private void startScan()
{
if(conn!=null)
{
conn.disconnect();
}
conn = new MediaScannerConnection(this, this);
conn.connect();
}
public void onMediaScannerConnected()
{
conn.scanFile(SCAN_PATH, FILE_TYPE);
}
public void onScanCompleted(String path, Uri uri)
{
try
{
if (uri != null)
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
startActivity(intent);
}
}
finally
{
conn.disconnect();
conn = null;
}
}
}
None of the above answers are correct, including the one marked as correct.
Here's the actual correct solution:
The secret is finding the bucket/album your folder is represented as. Buckets show up after a successful MediaScan so be sure any images/videos you want to show are first scanned as demonstrated multiple times above.
Let's assume I have an indexed folder in /sdcard/myapp/myappsmediafolder:
String bucketId = "";
final String[] projection = new String[] {"DISTINCT " + MediaStore.Images.Media.BUCKET_DISPLAY_NAME + ", " + MediaStore.Images.Media.BUCKET_ID};
final Cursor cur = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
while (cur != null && cur.moveToNext()) {
final String bucketName = cur.getString((cur.getColumnIndex(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME)));
if (bucketName.equals("myappsmediafolder")) {
bucketId = cur.getString((cur.getColumnIndex(MediaStore.Images.ImageColumns.BUCKET_ID)));
break;
}
}
Now that we have the bucketId for our album we can open it with a simple intent.
Filters Video files:
Uri mediaUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
Filters Image files:
Uri mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
...
if (bucketId.length() > 0) {
mediaUri = mediaUri.buildUpon()
.authority("media")
.appendQueryParameter("bucketId", bucketId)
.build();
}
Intent intent = new Intent(Intent.ACTION_VIEW, mediaUri);
startActivity(intent);
I can verify this works with the built-in Gallery app. Mileage may vary with other apps such as Google Photos.
I have yet to figure out how not to filter images/video, even though within Gallery you can select a specific Album with no filter.
I figured this out by looking at the AOSP source to the gallery app.
I don't have enough reputation to upvote or comment on his answer but ShellDude's answer allows you to put a directory URI in the gallery intent. So when the gallery app is opened it displays all of the images instead of 1.
For me, scanning my files like the answers above did not work. Querying the MediaStore.Images.Media.EXTERNAL_CONTENT_URI only worked after inserting new rows into the MediaStore.Images.Media.DATA table with the ContentResolver:
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, image.getPath());
values.put(MediaStore.Images.Media.MIME_TYPE,"image/jpeg");
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Here is a simplified one
private MediaScannerConnection conn;
private void notifySystemWithImage(final File imageFile) {
conn = new MediaScannerConnection(this, new MediaScannerConnectionClient() {
#Override
public void onScanCompleted(String path, Uri uri) {
try {
if (uri != null) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/*");
startActivity(intent);
}
} finally {
conn.disconnect();
conn = null;
}
}
#Override
public void onMediaScannerConnected() {
conn.scanFile(imageFile.getAbsolutePath(), "*/*");
}
});
conn.connect();
}
For those who this still give activity not found exception:
You need to specify directory of your inner application folder. Not user default root if images and everything.
public class SlideShow extends Activity implements MediaScannerConnectionClient {
public String[] allFiles;
private String SCAN_PATH ;
private static final String FILE_TYPE = "*/*";
private MediaScannerConnection conn;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
File folder = new File(HistoryActivity.this.getExternalFilesDir(null)+"/a/");
allFiles = folder.list();
SCAN_PATH= HistoryActivity.this.getExternalFilesDir(null)+"/a/"+allFiles[0];
Button scanBtn = (Button) findViewById(R.id.scanBtn);
scanBtn.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
startScan();
}
});
}
private void startScan()
{
if(conn!=null)
{
conn.disconnect();
}
conn = new MediaScannerConnection(this, this);
conn.connect();
}
public void onMediaScannerConnected()
{
conn.scanFile(SCAN_PATH, FILE_TYPE);
}
public void onScanCompleted(String path, Uri uri)
{
try
{
if (uri != null)
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
startActivity(intent);
}
}
finally
{
conn.disconnect();
conn = null;
}
}
}
works... but kitkat show only one photo. I managed to fix it for earlier versions with (updating gallery, when storing image):
public void savePhoto(Bitmap bmp)
{
File imageFileFolder = new File(context.getExternalFilesDir(null)+"/a/") ;
imageFileFolder.mkdir();
FileOutputStream out = null;
Calendar c = Calendar.getInstance();
String date = fromInt(c.get(Calendar.MONTH))
+ fromInt(c.get(Calendar.DAY_OF_MONTH))
+ fromInt(c.get(Calendar.YEAR))
+ fromInt(c.get(Calendar.HOUR_OF_DAY))
+ fromInt(c.get(Calendar.MINUTE))
+ fromInt(c.get(Calendar.SECOND));
File imageFileName = new File(imageFileFolder, date.toString() + ".jpg");
try
{
out = new FileOutputStream(imageFileName);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
scanPhoto(imageFileName.toString());
out = null;
} catch (Exception e)
{
e.printStackTrace();
}
}
public String fromInt(int val)
{
return String.valueOf(val);
}
public void scanPhoto(final String imageFileName)
{
msConn = new MediaScannerConnection(context,new MediaScannerConnection.MediaScannerConnectionClient()
{
public void onMediaScannerConnected()
{
msConn.scanFile(imageFileName, null);
Log.i("msClient obj in Photo Utility", "connection established");
}
public void onScanCompleted(String path, Uri uri)
{
msConn.disconnect();
Log.i("msClient obj in Photo Utility","scan completed");
}
});
msConn.connect();
}