In Android 7, the ContentResolver-openAssetFileDescriptor (vCardUri, "r") method returns an AssetFileDescriptor with a declared length of -1

In Android 7, getContentResolver().openAssetFileDescriptor(vCardUri, "r") returns an AssetFileDescriptor with a Length declaration of -1 returned by getDeclaredLength() .

Trying to export contacts as vcards to vcf file. The code I tried looks like this

 Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey); AssetFileDescriptor fd = resolver.openAssetFileDescriptor(uri, "r"); FileInputStream fis = fd.createInputStream(); byte[] b = new byte[(int)fd.getDeclaredLength()]; fis.read(b); 

The above code works fine on Android 6 or below. But when working with Android 7, the line creating the byte [] results in a NegativeByteArraySizeException , because the declared length is -1. When I debugged the loading of Android 7 sources, I noticed this problem. Any health will be really tangible.

+1
android android-7.0-nougat android-contentresolver android-contacts vcard
source share
3 answers

With @pskink, I found the following solution to my problem.

 String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); Uri vCardUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey); AssetFileDescriptor assetFileDescriptor; FileInputStream inputStream; try { assetFileDescriptor = getActivity().getContentResolver().openAssetFileDescriptor(vCardUri, "r"); if (assetFileDescriptor != null) { inputStream = assetFileDescriptor.createInputStream(); return readAsByteArray(inputStream); } } catch (FileNotFoundException e) { Log.e(TAG, "Vcard for the contact " + lookupKey + " not found", e); } catch (IOException e) { Log.e(TAG, "Problem creating stream from the assetFileDescriptor.", e); } 

where readAsByteArray () is written using code from Mihai Snippet .

Thanks @pskink

+3
source share

In your code, you use openAssestFileDescriptor, instead use openFileDescriptor because openAssestFileDescriptor is used to read the file in your resource folder, not the Uri file

  package com.daffo.stackoverflowtest; import android.Manifest; import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.provider.ContactsContract; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { Cursor cursor; ArrayList<String> vCard; String vfile; private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100; /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); vfile = "Contacts" + "_" + System.currentTimeMillis() + ".vcf"; /**This Function For Vcard And here i take one Array List in Which i store every Vcard String of Every Conatact * Here i take one Cursor and this cursor is not null and its count>0 than i repeat one loop up to cursor.getcount() means Up to number of phone contacts. * And in Every Loop i can make vcard string and store in Array list which i declared as a Global. * And in Every Loop i move cursor next and print log in logcat. * */ addContactPermissions(); } /** * Show the contacts in the ListView. */ private void addContactPermissions() { // Check the SDK version and whether the permission is already granted or not. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) { requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_READ_CONTACTS); //After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method } else { // Android version is lesser than 6.0 or the permission is already granted. getVcardString(); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission is granted getVcardString(); } else { Toast.makeText(this, "Until you grant the permission, we canot display the names", Toast.LENGTH_SHORT).show(); } } } private void getVcardString() { // TODO Auto-generated method stub vCard = new ArrayList<String>(); cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); for (int i = 0; i < cursor.getCount(); i++) { get(cursor); if (vCard.size() > 0) { Log.d("TAG", "Contact " + (i + 1) + "VcF String is" + vCard.get(i)); } cursor.moveToNext(); } } else { Log.d("TAG", "No Contacts in Your Phone"); } } public void get(Cursor cursor) { //cursor.moveToFirst(); String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey); ParcelFileDescriptor fd; try { fd = this.getContentResolver().openFileDescriptor(uri, "r"); // Your Complex Code and you used function without loop so how can you get all Contacts Vcard.?? /* FileInputStream fis = fd.createInputStream(); byte[] buf = new byte[(int) fd.getDeclaredLength()]; fis.read(buf); String VCard = new String(buf); String path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile; FileOutputStream out = new FileOutputStream(path); out.write(VCard.toString().getBytes()); Log.d("Vcard", VCard);*/ FileInputStream fis = new FileInputStream(fd.getFileDescriptor()); byte[] buf = new byte[fis.available()]; fis.read(buf); String vcardstring = new String(buf); vCard.add(vcardstring); String storage_path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile; FileOutputStream mFileOutputStream = new FileOutputStream(storage_path, false); mFileOutputStream.write(vcardstring.toString().getBytes()); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } 
0
source share

In Android Nougat:

 byte[] b = new byte[(int)fd.getDeclaredLength()]; 

fd.getDeclaredLength () returns -1.

Check out my answer here link .

0
source share

All Articles