Hello my fellow stackoverflows,
I am writing an application where I implemented an Activity that handles share-intents.
So far it works fine but during testing I have got a problem with Quickoffice (Android 4.4, KitKat),
because it returns an URI from which I can´t get the filename from. I also tried sharing with other apps like Dropbox and it works there.
The exact URI I get from the Qickoffice app:
content://com.quickoffice.android.quickcommon.FileContentProvider/5cmeDeeatcdv8IFyu-bEr2w1jSHrvPmCzXGb_VvZulMBErE5Tmfd_5P5kckE68LaEYDVSp3q5r19%0A4sOkpYCEM_VqK6Y%3D%0A
This was the code I used first:
public String getRealPathFromURI(Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA}; // = "_data"
ContentResolver cr = getContentResolver();
cursor = cr.query(contentUri, proj, null, null, null); // <--EXCEPTION
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception exception) {
Log.d("clixend", "Exception: " + exception);
Toast.makeText(this, "Exception: " + exception, Toast.LENGTH_LONG).show();
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
Where I received following error:
09-23 16:54:17.664 32331-32341/? E/DatabaseUtils﹕ Writing exception to parcel
java.lang.UnsupportedOperationException: Unsupported column: _data
at com.google.android.apps.docs.quickoffice.FileContentProvider.query(FileContentProvider.java:78)
at android.content.ContentProvider.query(ContentProvider.java:857)
at android.content.ContentProvider$Transport.query(ContentProvider.java:200)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
After some research I figured out that Android 4.4 Kitkat introduces SAF (Storage Access Framework) which manages data different, so I tried the following Code from https://developer.android.com/guide/topics/providers/document-provider.html to get the name:
public String getNameKitkat(Uri contentUri) {
Cursor cursor = getContentResolver()
.query(contentUri, null, null, null, null, null); // <--EXCEPTION
try {
if (cursor != null && cursor.moveToFirst()) {
String displayName = cursor.getString(
cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
return displayName;
}
} finally {
cursor.close();
}
return null;
}
But I also receive an error code:
09-23 16:49:43.317 32331-32421/? E/DatabaseUtils﹕ Writing exception to parcel
java.lang.IllegalArgumentException: columnNames.length = 4, columnValues.size() = 2
at android.database.MatrixCursor.addRow(MatrixCursor.java:157)
at android.database.MatrixCursor.addRow(MatrixCursor.java:128)
at com.google.android.apps.docs.quickoffice.FileContentProvider.query(FileContentProvider.java:95)
at android.content.ContentProvider.query(ContentProvider.java:857)
at android.content.ContentProvider$Transport.query(ContentProvider.java:200)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
If somebody knows how to get the name out of the URI I get from Quickoffice I would be very thankful.
After I searched some more I found the answer to my question how to get the filename from the URI I get from Quickoffice.
public String getNameFromURI(Uri contenturi){
String[] proj = {
OpenableColumns.DISPLAY_NAME,
OpenableColumns.SIZE
};
String name = null;
int size= 0;
Cursor metadataCursor = getContentResolver().query(contenturi, proj, null, null, null);
if (metadataCursor != null) {
try {
if (metadataCursor.moveToFirst()) {
name = metadataCursor.getString(0);
size = metadataCursor.getInt(1);
}
} finally {
metadataCursor.close();
}
}
return name;
}
The problem was I didn´t use the proper Typ, I wanted to receive.
After using:
String[] proj = {
OpenableColumns.DISPLAY_NAME,
OpenableColumns.SIZE
};
it worked perfectly fine.
Sorry for your waste of time.
Related
I am successfully able to select file programmatically. But, when I am getting uri from that file
content://com.android.providers.downloads.documents/document/3356
content://com.android.providers.downloads.documents/document/3331
Unfortunately, wherever the file is my uri is always locating at downloads.documents
I think it doesn't fact. Cause, everyone get the uri by data.getData(). So, I think the uri is correct.
Last year, I was working with Audio, Video, File and Image uploading to server. I was trying that source code to get path.
String mediaPath, mediaPath1;
String[] mediaColumns = {MediaStore.Video.Media._ID};
// Get the file from data
String path = data.getStringExtra(mediaPath);
File file = new File(path);
Uri selectedFile = Uri.fromFile(new File(file.getAbsolutePath()));
String[] filePathColumn = {MediaStore.Files.FileColumns.MEDIA_TYPE};
Cursor cursor = getContentResolver().query(selectedFile, filePathColumn, null, null, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mediaPath = cursor.getString(columnIndex);
txt.setText(path);
// Set the Image in ImageView for Previewing the Media
cursor.close();
Unfortunately,That is returning null pointerexception. After researching little bit, I found another source code(PathUtils)
public class PathUtils {
public static String getPath(final Context context, final Uri uri) {
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {// ExternalStorageProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
String storageDefinition;
if("primary".equalsIgnoreCase(type)){
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else {
if(Environment.isExternalStorageRemovable()){
storageDefinition = "EXTERNAL_STORAGE";
} else{
storageDefinition = "SECONDARY_STORAGE";
}
return System.getenv(storageDefinition) + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {// DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) {// MediaProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore (and general)
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {// File
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}
I am not getting any error. But, Path is always locating at Downloads file. I don't know why. After looking at uri I noticed my uri is always returning downloads.documents. I am not sure is it the issue.
There is lot of question similar to this question in stackoverflow. To tell everyone none worked for me. So, I will request to not flag it.
PATH: /storage/emulated/0/Download/The Road to Reality ( PDFDrive ).pdf
PATH: /storage/emulated/0/Download/The order of time ( PDFDrive ).pdf
PATH: /storage/emulated/0/Download/pdf_495.pdf
First pdf file is in documents file. Second pdf file is in Download third pdf file is in /storage/emulated/0/
I am parsing pdf texts. Here is my code
try {
String parsedText="";
StringBuilder builder = new StringBuilder();
//Here you can see I need path to load the pdf file
PdfReader reader = new PdfReader(PathUtils.getPathFromUri(getApplicationContext(),PathHolder));
int n = reader.getNumberOfPages();
for (int i = 10; i <n ; i++) {
parsedText = parsedText+ PdfTextExtractor.getTextFromPage(reader, i).trim()+"\n";
Log.d("for_loop", String.valueOf(i));
Log.d("PARSED_TEXT",parsedText+" ");
}
builder.append(parsedText);
reader.close();
runOnUiThread(() -> {
txt.setText(builder.toString());
});
// System.out.println("TEXT FROM PDF : "+builder.toString());
} catch (Exception e) {
System.out.println(e);
}
As you can see I need path to load the pdf file. But, I have already told you I am having issue with path. So, if I wanna do something with uri than how can i do that cause, path required.
I tried another way to get the path also.
Uri PathHolder = data.getData();
Cursor cursor = null;
try {
cursor = this.getContentResolver().query(PathHolder, new String[]{MediaStore.Files.FileColumns.DATA}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
String path = Environment.getExternalStorageDirectory().toString()+"/" + fileName;
Log.d("PATH",path);
if (!TextUtils.isEmpty(path)) {
}else{
Toast.makeText(this, "null return", Toast.LENGTH_SHORT).show();
}
}
}catch (Exception e){
e.printStackTrace();
Log.d("EXCEPTION_ERROR",e.toString());
} finally {
if (cursor != null)
cursor.close();
}
Unfortunately, It's not working also.
Like we do for audio, images or, videos.
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Audio.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mediaPath = cursor.getString(columnIndex);
str1.setText(mediaPath);
// Set the Image in ImageView for Previewing the Media
imgView.setImageBitmap(BitmapFactory.decodeFile(mediaPath));
cursor.close();
Edited :
Uri uri = data.getData();
try{
InputStream in = getContentResolver().openInputStream(uri);
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
for (String line; (line = r.readLine()) != null; ) {
total.append(line).append('\n');
}
String content = total.toString();
Log.d("CONTENT",content);
}catch (Exception e){
e.printStackTrace();
}
The problem I am facing here is.
As you can see the catch is returning no such file or directory found. I am not sure what I am doing wrong here. Cause, I took the source code from somewhere else and it is first time I am working with InputStream. And, I think the problem is on I am unable to get the file by uri.
Catch exception is returning
no such file or directory
Edited :
Uri uri = data.getData();
File file=new File(uri.toString());
InputStream inputStream = getContentResolver().openInputStream(uri);
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=inputStream.read(buf))>0){
out.write(buf,0,len);
}
out.close();
inputStream.close();
Starting from Android 10 using Scoped Storage is required. You cannot get absolute path of the file and work with file APIs with external Storage. MediaStore.Audio.Media.DATA that is used to take absolute path is depracated. But with uri returned you can copy that file using inputStream to your app-specific directory and do what you want with that file. For more information please refer to this article.
For reading pdf as I said you can copy that file to your app-specific directory or use that uri like this sample.
Copying file from uri in kotlin:
val uri: Uri = data?.data ?: return
val ins = context?.contentResolver?.openInputStream(uri)
val file = File(context?.filesDir, "image.jpg")
val fileOutputStream = FileOutputStream(file)
ins?.copyTo(fileOutputStream)
ins?.close()
fileOutputStream.close()
val absolutePath = file.absolutePath
Log.d("AAA", absolutePath)
If you use java there is no copyTo function so use this function then you can use the file in Files directory in app-specific storage
private void copyInputStreamToFile( InputStream in, File file ) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}}
Copied file in app-specific directory
This is log:
D/AAA: /data/user/0/com.example.pickerapp/files/image.jpg
I want to get the name for incoming call number from contact list through the following method. it work on all android version but it give null in android 9.0 pie.
private String getContactName(String number, Context context) {
String contactName = "";
String[] projection = new String[] {
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup.NUMBER,
ContactsContract.PhoneLookup.HAS_PHONE_NUMBER };
Uri contactUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
Cursor cursor = context.getContentResolver().query(contactUri,
projection, null, null, null);
if(cursor != null) {
if (cursor.moveToFirst()) {
contactName = cursor.getString(cursor
.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
}
cursor.close();
}
return contactName.equals("") ? number : contactName;
}
i also try a new method but it also not working and give me null value. i get this code from google developer documentation. whats wrong with my code or please help me on which method i can get contact name for a number.
public String onCreateIncomingConnection (String s) {
// Get the telephone number from the incoming request URI.
String phoneNumber = s;
String displayName = "Unknown caller";
boolean isCallerInWorkProfile = false;
// Look up contact details for the caller in the personal and work profiles.
Uri lookupUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
Uri.encode(phoneNumber));
Cursor cursor = getContentResolver().query(
lookupUri,
new String[]{
ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup.CUSTOM_RINGTONE
},
null,
null,
null);
// Use the first contact found and check if they're from the work profile.
if (cursor != null) {
try {
if (cursor.moveToFirst() == true) {
displayName = cursor.getString(1);
isCallerInWorkProfile =
ContactsContract.Contacts.isEnterpriseContactId(cursor.getLong(0));
}
} finally {
cursor.close();
}
}
// Return a configured connection object for the incoming call.
// MyConnection connection = new MyConnection();
// connection.setCallerDisplayName(displayName, TelecomManager.PRESENTATION_ALLOWED);
//
// Our app's activity uses this value to decide whether to show a work badge.
// connection.setIsCallerInWorkProfile(isCallerInWorkProfile);
// Configure the connection further ...
return displayName;
}
I am developing an android application, in which I am displaying call Logs and the Details of the calls.
I want to display the contact picture in the call Log.
I am able to get the contact ID and the uri from the Contact id but I am getting the below exception for all the contacts:
java.io.FileNotFoundException: File does not exist; URI: content://com.android.contacts/contacts/171
Here is the below code which I tried:
Cursor managedCursor = getContentResolver().query( CallLog.Calls.CONTENT_URI,null, null,null, android.provider.CallLog.Calls.DEFAULT_SORT_ORDER);
while ( managedCursor.moveToNext() )
{
contactId = getContactIDFromNumber(phNumber,this);
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
}
public static int getContactIDFromNumber(String contactNumber,Context context)
{
int phoneContactID = new Random().nextInt();
Cursor contactLookupCursor = context.getContentResolver().query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,Uri.encode(contactNumber)),new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup._ID}, null, null, null);
while(contactLookupCursor.moveToNext()){
phoneContactID = contactLookupCursor.getInt(contactLookupCursor.getColumnIndexOrThrow(PhoneLookup._ID));
}
contactLookupCursor.close();
return phoneContactID;
}
public static Bitmap getContactBitmapFromURI(Context context, Uri uri)
{
InputStream input = null;
try
{
input = context.getContentResolver().openInputStream(uri);
//input = Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
if (input == null)
{
return null;
}
return BitmapFactory.decodeStream(input);
}
I have an activity that when users press "share" on a file it would open my app and start uploading the file. Now this works perfectly with images because the URI returned is for MediaStore. But I want to be able to return the URI from any source such as from ES File Explorer
Here is the current code:
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);
}
How can I make this so instead of MediaStore it will be used for any type of file?
I'd recommend skipping the path step (if possible) and going straight to getting an InputStream which can simplify things a bit:
public InputStream getInputStream(Uri uri) {
InputStream stream = null;
String scheme = uri.getScheme();
try {
if (ContentResolver.SCHEME_CONTENT.equals(scheme) || ContentResolver.SCHEME_FILE.equals(scheme) || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
stream = getContentResolver().openInputStream(uri);
} else if ("https".equals(scheme) || "http".equals(scheme)) {
// ContentResolver can't handle web uris. Handle or skip them as you see fit.
}
} catch (FileNotFoundException e) {
// Handle the exception however you see fit.
}
return stream;
}
I'd favor using the ContentResolver and letting it sort out the specifics... For example, what happens if you get a content uri that isn't related to the MediaStore? By letting the ContentResolver handle that, you don't have to care.
You can't do that. You can use it for the media store, beacuse the path of those images are stored in the built in SQLite database, but the files on your sd card has no entries in the database.
You can check if the URI's scheme is content or file, and use different methods to access the file the following way:
public String getPath(Uri uri) {
if(uri.getScheme().equals("content")){
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);
} else if(uri.getScheme().equals("file")){
File myFile = new File(uri);
return myFile.getAbsolutePath();
}
}
I have been developing the application which must recognize SMS commands. So, I need to know how I can get the last sms. I know that I need to use BroadcastReceiver (and I use it), but I don't know how I can get the last sms in this class. Please, help me with it, I hope you can do it. Thank you in advance.
thanks Bo for the link to my blog.
To get the last message from your embeded android database (sqlite) you have at first create a cursor instance.
Cursor cursor = context.getContentResolver().query("content://sms", null, null, null, null);
and then move to the first sms (the first is the last receiver ;))
cursor.moveToFirst();
Look at my blog how I did it as Bo told you ;)
// removed link
Cheers
see below code it may help you.
Uri myMessage = Uri.parse("content://sms/");
ContentResolver cr = con.getContentResolver();
Cursor c = cr.query(myMessage, new String[] { "_id",
"address", "date", "body", "read" }, null,
null, null);
startManagingCursor(c);
Main_calss.getSmsLogs(c, con);
public static final ArrayList<String> sms_num = new ArrayList<String>();
public static final ArrayList<String> sms_body = new ArrayList<String>();
public static void getSmsLogs(Cursor c, Context con) {
if (sms_num.size() > 0) {
sms_num.clear();
sms_body.clear();
}
try {
if (c.moveToFirst()) {
do {
Log.d("error",
""
+ c.getString(c
.getColumnIndexOrThrow("address")));
if (c.getString(c.getColumnIndexOrThrow("address")) == null) {
c.moveToNext();
continue;
}
String Number = c.getString(
c.getColumnIndexOrThrow("address")).toString();
String Body = c.getString(c.getColumnIndexOrThrow("body"))
.toString();
sms_num.add(Number);
sms_body.add(Body);
} while (c.moveToNext());
}
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
now get last massage you have to do this.
sms_num.get(sms_num.size()-1);
sms_body.get(sms_num.size()-1);
if it is correct then make it right.