Similar threads here do not have answers that helped...
I want to create email message with file attach, file is on internal storage.
Here is code:
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_EMAIL , new String[]{email});
i.putExtra(Intent.EXTRA_SUBJECT, "Smart Weight Tracker");
i.putExtra(Intent.EXTRA_TEXT , "CSV file is in attachment");
Uri uri;
if(useExternal){
uri = Uri.fromFile(new File(this.getExternalFilesDir(null),fname));
}
else{
File f = new File(this.getFilesDir(),fname);
f.setReadable(true, false);
f.setWritable(true, false);
uri = Uri.fromFile(f);
}
i.putExtra(Intent.EXTRA_STREAM, uri);
try {
startActivity(Intent.createChooser(i, "Send mail..."));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(MainActivity.this, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
}
It works perfectly with external storage, but i have no attach when use internal storage.
I checked - file opens, (it's length in my app by showing Toast - is OK, > 0).
I write it this way:
OutputStreamWriter out =
new OutputStreamWriter(con.openFileOutput(fname, Context.MODE_WORLD_READABLE));
In logcat i see
I/Gmail (28480): >>>>> Attachment uri: file:///data/data/Android.MyApp/files /31.10.2011.csv
I/Gmail (28480): >>>>> type: text/plain
I/Gmail (28480): >>>>> name: 31.10.2011.csv
I/Gmail (28480): >>>>> size: 0
Size == 0!
Any ideas?
Hi,
Try to use content providers.
emailIntent.putExtra(Intent.EXTRA_STREAM,Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/"+ fileName));
........
Android: Attaching files from internal cache to Gmail
package com.stephendnicholas.gmailattach;
import java.io.File;
import java.io.FileNotFoundException;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
public class CachedFileProvider extends ContentProvider {
private static final String CLASS_NAME = "CachedFileProvider";
// The authority is the symbolic name for the provider class
public static final String AUTHORITY = "com.stephendnicholas.gmailattach.provider";
// UriMatcher used to match against incoming requests
private UriMatcher uriMatcher;
#Override
public boolean onCreate() {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// Add a URI to the matcher which will match against the form
// 'content://com.stephendnicholas.gmailattach.provider/*'
// and return 1 in the case that the incoming Uri matches this pattern
uriMatcher.addURI(AUTHORITY, "*", 1);
return true;
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
String LOG_TAG = CLASS_NAME + " - openFile";
Log.v(LOG_TAG,
"Called with uri: '" + uri + "'." + uri.getLastPathSegment());
// Check incoming Uri against the matcher
switch (uriMatcher.match(uri)) {
// If it returns 1 - then it matches the Uri defined in onCreate
case 1:
// The desired file name is specified by the last segment of the
// path
// E.g.
// 'content://com.stephendnicholas.gmailattach.provider/Test.txt'
// Take this and build the path to the file
String fileLocation = getContext().getCacheDir() + File.separator
+ uri.getLastPathSegment();
// Create & return a ParcelFileDescriptor pointing to the file
// Note: I don't care what mode they ask for - they're only getting
// read only
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(
fileLocation), ParcelFileDescriptor.MODE_READ_ONLY);
return pfd;
// Otherwise unrecognised Uri
default:
Log.v(LOG_TAG, "Unsupported uri: '" + uri + "'.");
throw new FileNotFoundException("Unsupported uri: "
+ uri.toString());
}
}
// //////////////////////////////////////////////////////////////
// Not supported / used / required for this example
// //////////////////////////////////////////////////////////////
#Override
public int update(Uri uri, ContentValues contentvalues, String s,
String[] as) {
return 0;
}
#Override
public int delete(Uri uri, String s, String[] as) {
return 0;
}
#Override
public Uri insert(Uri uri, ContentValues contentvalues) {
return null;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Cursor query(Uri uri, String[] projection, String s, String[] as1,
String s1) {
return null;
}
}
<provider android:name="CachedFileProvider" android:authorities="com.stephendnicholas.gmailattach.provider">
public static void createCachedFile(Context context, String fileName,
String content) throws IOException {
File cacheFile = new File(context.getCacheDir() + File.separator
+ fileName);
cacheFile.createNewFile();
FileOutputStream fos = new FileOutputStream(cacheFile);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
PrintWriter pw = new PrintWriter(osw);
pw.println(content);
pw.flush();
pw.close();
}
public static Intent getSendEmailIntent(Context context, String email,
String subject, String body, String fileName) {
final Intent emailIntent = new Intent(
android.content.Intent.ACTION_SEND);
//Explicitly only use Gmail to send
emailIntent.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail");
emailIntent.setType("plain/text");
//Add the recipients
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL,
new String[] { email });
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
//Add the attachment by specifying a reference to our custom ContentProvider
//and the specific file of interest
emailIntent.putExtra(
Intent.EXTRA_STREAM,
Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/"
+ fileName));
return emailIntent;
}
http://stephendnicholas.com/archives/974#comment-342
Uri fileUri = Uri.fromFile(new File(context.getCacheDir()+ "/"+ fileName));
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,
"Test Subject");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,
"go on read the emails");
emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
startActivity(emailIntent);
Please try this code. Hope this would help.
I was following the stephendnicholas code for hours thinking I HAD to write my files to internal storage because my device had no sd card.
Creating my "internal" file like this worked just fine for me:
File file = new File(getExternalFilesDir(null), filename); // :)
It avoided Gmail limitations during attachment.
Before this I was creating my file object like this:
File file = new File(this.getFilesDir(), filename); //will not attach
But if your file is literally from internal storage, then stephendnicholas content providers etc. work if you have mad android skills.
Related
I want to attach a file I generate on runtime.
Runtime flow:
Create intent
Create a file under cacheDir
Add file as content:// extra to the intent
Start chooser and select Gmail
expect openFile() to be called and allow access
Gmail opens with no attachment
However, openFile() isn't called.
Here is the relevant code:
Create an intent and add extras:
public static void contact(Activity activity, String message) {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
String version = Version.appVersion(activity);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{activity.getString(R.string.contact_email)});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, activity.getString(R.string.app_name)+" ("+version+")");
emailIntent.putExtra(Intent.EXTRA_TEXT, message);
addInfoAttachment(emailIntent, activity);
String title = activity.getString(R.string.string_select_email_app);
activity.startActivity(Intent.createChooser(emailIntent, title));
}
Create the cached file:
public static void createCachedFile(Context context, String fileName,
String content) throws IOException
{
File cacheFile = new File(context.getCacheDir() + File.separator
+ fileName);
cacheFile.delete();
cacheFile.createNewFile();
FileOutputStream fos = new FileOutputStream(cacheFile);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
PrintWriter pw = new PrintWriter(osw);
pw.println(content);
pw.flush();
pw.close();
}
Add the file to the intent:
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + AUTHORITY + File.separator + REPORT_INFO_FILE_NAME));
Overriding ContentProvider: (not called)
public class LogFileProvider extends ContentProvider {
private static final String TAG = "LogFileProvider";
public static final String AUTHORITY = "com.domain.appName.LogFileProvider";
private UriMatcher uriMatcher;
#Override
public boolean onCreate() {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "*", 1);
return true;
}
#Override
public ParcelFileDescriptor openFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
Log.v(TAG, "openFile Called with uri: '" + uri + "'." + uri.getLastPathSegment());
// Check incoming Uri against the matcher
switch (uriMatcher.match(uri)) {
// If it returns 1 - then it matches the Uri defined in onCreate
case 1:
String fileLocation = getContext().getCacheDir() + File.separator
+ uri.getLastPathSegment();
return ParcelFileDescriptor.open(new File(
fileLocation), ParcelFileDescriptor.MODE_READ_ONLY);
default:
Log.v(TAG, "Unsupported uri: '" + uri + "'.");
throw new FileNotFoundException("Unsupported uri: "
+ uri.toString());
}
}
// //////////////////////////////////////////////////////////////
// Not supported / used / required for this example
// //////////////////////////////////////////////////////////////
#Override
public int update(#NonNull Uri uri, ContentValues contentvalues, String s,
String[] as) {
return 0;
}
#Override
public int delete(#NonNull Uri uri, String s, String[] as) {
return 0;
}
#Override
public Uri insert(#NonNull Uri uri, ContentValues contentvalues) {
return null;
}
#Override
public String getType(#NonNull Uri uri) {
return null;
}
#Override
public Cursor query(#NonNull Uri uri, String[] projection, String s, String[] as1,
String s1) {
return null;
}
}
In manifest:
<provider
android:name=".LogFileProvider"
android:authorities="com.domain.appName.LogFileProvider"
android:enabled="true"
android:exported="false"
android:grantUriPermissions="true"/>
You need to add FLAG_GRANT_READ_URI_PERMISSION to the Intent. As it stands, the recipient has no rights to access that content.
You might consider using FileProvider rather than bothering with your own. Some clients will expect the provider to do more than what you have (e.g., respond to query() for the OpenableColumns, respond to getType() with the actual MIME type).
I have an application which open pdf file with tap on app (default PDF in raw folder), openwith (myapp) and also from mail attachment. I converted the selected PDF file into inputstream and then to bytearray. Now I have a button and when user click on it need to send email through gmail app using intent. I need to add inputstream or bytearray as pdffile to the mail as attachment.I used the following code I can see the attachment with no bytes and received email donot have attachment. Struggling from more than 10 hours.. please help...
Intent sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.setType("application/pdf");
sendIntent.setData(Uri.parse("sample#gmailcom"));
sendIntent.setClassName("com.google.android.gm", "com.google.android.gm.ComposeActivityGmail");
sendIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { "sample#gmail.com" });
sendIntent.putExtra(Intent.EXTRA_SUBJECT, "testPDF");
sendIntent.putExtra(Intent.EXTRA_TEXT, "this is a PDF ");
File fileIn = new File(name, "myfile.pdf");
Toast.makeText(this, fileIn.getName(), Toast.LENGTH_LONG).show();
Uri fileuri = Uri.fromFile(fileIn);
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileuri.toString()));
startActivity(sendIntent);
I tried many ways and finally found a solutions myself. Use file provider to attach the file to mail without storing it physically on the device. The code is follows and hope it helps someone else.
Add a class AttachFileProvider with below code
public class AttachFileProvider extends ContentProvider {
private static final String CLASS_NAME = "AttachFileProvider";
// The authority is the symbolic name for the provider class
public static final String AUTHORITY = "com.example.pDoc.pdocsigner.provider";
// UriMatcher used to match against incoming requests<br />
private UriMatcher uriMatcher;
#Override
public boolean onCreate() {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// Add a URI to the matcher which will match against the form
uriMatcher.addURI(AUTHORITY, "*", 1);
return true;
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
// Check incoming Uri against the matcher
switch (uriMatcher.match(uri)) {
// If it returns 1 - then it matches the Uri defined in onCreate
case 1:
// The desired file name is specified by the last segment of the path
// Take this and build the path to the file
String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment();
// Create & return a ParcelFileDescriptor pointing to the file
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY);
return pfd;
// Otherwise unrecognised Uri
default:
//Log.v(LOG_TAG, "Unsupported uri: '" + uri + "'.");
throw new FileNotFoundException("Unsupported uri: " + uri.toString());
}
}
// //////////////////////////////////////////////////////////////
// Not supported / used / required for this example
// //////////////////////////////////////////////////////////////
#Override
public int update(Uri uri, ContentValues contentvalues, String s, String[] as) { return 0; }
#Override
public int delete(Uri uri, String s, String[] as) { return 0; }
#Override
public Uri insert(Uri uri, ContentValues contentvalues) { return null; }
#Override
public String getType(Uri uri) { return null; }
#Override
public Cursor query(Uri uri, String[] projection, String s, String[] as1, String s1) { return null; }
}
to attach the mail use the following code.
if (bytes.length > 0) {
try {
createCachedFile(this, attachmentFileName, bytes);
this.startActivity(getSendEmailIntent(this, "tomailid", "Test", "See attached", attachmentFileName));
} catch (IOException e) {
e.printStackTrace();
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "Gmail is not available on this device.", Toast.LENGTH_SHORT).show();
}
}
public void createCachedFile(Context context, String fileName, byte[] content) throws IOException {
File cacheFile = new File(context.getCacheDir() + File.separator + fileName);
cacheFile.createNewFile();
BufferedOutputStream bostream = new BufferedOutputStream(new FileOutputStream(cacheFile));
bostream.write(content);
bostream.flush();
bostream.close();
}
public static Intent getSendEmailIntent(Context context, String email, String subject, String body, String fileName) {
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
//Explicitly only use Gmail to send
// emailIntent.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail");
//emailIntent.setType("message/rfc822");
emailIntent.setType("vnd.android.cursor.item/email");
//Add the recipients
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] { email });
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
//Add the attachment to custom ContentProvider
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + AttachFileProvider.AUTHORITY + "/" + fileName));
return emailIntent;
}
You should make sure that you attachment file can be read by gmail app, so put it in the external sdcard storage area. Maybe you path has problem, change it and test.
In my application, a number of contacts are attached to single .vcf file and that file sent to mail, try to this one all contacts data display in log cat, but unable to send all data attached to single .vcf file?
Anyone have an idea regarding this help me, please.
here is my code
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
vCard = new ArrayList<String>();
Log.i("TAG one", "vfile" +vfile);
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 Contact 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.
* */
getVcardString();
}
private void getVcardString() {
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
Log.i("TAG two", "cursor" +cursor);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
Log.i("Number of contacts", "cursorCount" +cursor.getCount());
for (int i = 0; i < cursor.getCount(); i++) {
get(cursor);
Log.i("TAG send contacts", "Contact " + (i + 1) + "VcF String is" + vCard.get(i));
cursor.moveToNext();
}
StringBuffer s = new StringBuffer();
s.append( vCard.toString());
string = s.toString();
file = new File(string);
// Log.i("s", ""+s);
// Log.i("string", ""+string);
Log.i("file", ""+file);
} else {
Log.i("TAG", "No Contacts in Your Phone");
}
}
public void get(Cursor cursor) {
String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Log.i("lookupKey", ""+lookupKey);
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
try {
AssetFileDescriptor fd = this.getContentResolver().openAssetFileDescriptor(uri, "r");
FileInputStream fis = fd.createInputStream();
byte[] buf = new byte[(int) fd.getDeclaredLength()];
fis.read(buf);
String vcardstring= new String(buf);
String storage_path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile;
FileOutputStream mFileOutputStream = new FileOutputStream(storage_path, true);
mFileOutputStream.write(vcardstring.toString().getBytes());
vCard.add(storage_path);
} catch (Exception e1) {
e1.printStackTrace();
}
}
private void data() {
File filelocation = file;
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("vnd.android.cursor.dir/email");
sharingIntent.setType("application/x-vcard");
sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+filelocation));
startActivity(Intent.createChooser(sharingIntent, "Send email"));
}
}
finally my issue is solved using like this
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = this;
button = (Button) findViewById(R.id.send);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
data();
}
});
/**
* This Function For Vcard And here i take one Array List in Which i
* store every Vcard String of Every Contact 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.
* */
getVcardString();
}
public static void getVcardString() {
String path = null;
String vfile = null;
vfile = "Contacts.vcf";
Cursor phones = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
null, null, null);
phones.moveToFirst();
Log.i("Number of contacts", "cursorCount" +phones.getCount());
for(int i =0;i<phones.getCount();i++) {
String lookupKey = phones.getString(phones.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Log.i("lookupKey", " " +lookupKey);
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
AssetFileDescriptor fd;
try {
fd = mContext.getContentResolver().openAssetFileDescriptor(uri, "r");
FileInputStream fis = fd.createInputStream();
byte[] buf = new byte[(int) fd.getDeclaredLength()];
fis.read(buf);
String VCard = new String(buf);
path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile;
FileOutputStream mFileOutputStream = new FileOutputStream(path, true);
mFileOutputStream.write(VCard.toString().getBytes());
phones.moveToNext();
filevcf = new File(path);
Log.i("file", "file" +filevcf);
}catch(Exception e1) {
e1.printStackTrace();
}
}
Log.i("TAG", "No Contacts in Your Phone");
}
protected void data() {
File filelocation = filevcf ;
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("vnd.android.cursor.dir/email");
sharingIntent.setType("application/x-vcard");
sharingIntent.putExtra(Intent.EXTRA_EMAIL, "mail#gmail.com" );
sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+filelocation.getAbsolutePath()));
startActivity(Intent.createChooser(sharingIntent, "Send email"));
}
I successfully tested the following. Changes to your code are indicated with comments beginning with "CHANGE:". Don't forget to have android.permission.WRITE_EXTERNAL_STORAGE in your manifest.
public class MainActivity extends Activity {
private String vfile;
private Cursor cursor;
private ArrayList<String> vCard;
private String string;
private File file;
private String storage_path; //CHANGE: storage_path global
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vCard = new ArrayList<String>();
Log.i("TAG one", "vfile" + vfile);
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 Contact 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.
* */
getVcardString();
data(); //CHANGE: now calling data to send vCard intent
}
private void getVcardString() {
cursor = getContentResolver().
query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null, null);
Log.i("TAG two", "cursor" +cursor);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
Log.i("Number of contacts", "cursorCount" +cursor.getCount());
for (int i = 0; i < cursor.getCount(); i++) {
get(cursor);
Log.i("TAG send contacts",
"Contact " + (i + 1) + "VcF String is" + vCard.get(i));
cursor.moveToNext();
}
// StringBuffer s = new StringBuffer(); CHANGE: not needed
// s.append( vCard.toString());
// string = s.toString();
// file = new File(string); //CHANGE: this is not what file should be
} else {
Log.i("TAG", "No Contacts in Your Phone");
}
}
public void get(Cursor cursor) {
String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Log.i("lookupKey", ""+lookupKey);
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
try {
AssetFileDescriptor fd = this.getContentResolver().openAssetFileDescriptor(uri, "r");
FileInputStream fis = fd.createInputStream();
byte[] buf = new byte[(int) fd.getDeclaredLength()];
fis.read(buf);
String vcardstring= new String(buf);
vCard.add(vcardstring); //CHANGE: added this, so log statement in above method doesn't generate error
// String storage_path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile;
//CHANGE: this is the path we need to get file for intent:
storage_path = getExternalFilesDir(null).toString() + File.separator + vfile;
Log.i("MainActivity", storage_path);
//CHANGE: this will create the file we need:
file = new File(getExternalFilesDir(null), vfile);
file.createNewFile(); //CHANGE
//CHANGE: this will create the stream we need:
FileOutputStream mFileOutputStream = new FileOutputStream(file, true);
mFileOutputStream.write(vcardstring.toString().getBytes());
mFileOutputStream.close(); //don't forget to close
// vCard.add(storage_path); //CHANGE: not needed
} catch (Exception e1) {
e1.printStackTrace();
}
}
private void data() {
// File filelocation = file; //CHANGE: not what we need
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("vnd.android.cursor.dir/email");
sharingIntent.setType("application/x-vcard");
//CHANGE: using correct path:
sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(storage_path));
startActivity(Intent.createChooser(sharingIntent, "Send email"));
}
}
I have some images stored in getExternalFilesDir() and i am trying to show those images in the android gallery (cooliris).
Right now i have been doing this:
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(imgPath,"image/*");
startActivity(intent);
But nothing happens.
I have changed the setDataAndType to this:
intent.setDataAndType(Uri.fromFile(new File(imgPath)),"image/*");
This way it works, but it takes 5-10 seconds for the gallery to go from a black screen to showing my image.
Anyway to solve this or any better approach?
By implementing a file content provider you will be able to avoid this 5-10 second delay
import java.io.File;
import java.io.FileNotFoundException;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
public class FileContentProvider extends ContentProvider {
private static final String AUTHORITY = "content://com.yourprojectinfo.fileprovider";
public static Uri constructUri(String url) {
Uri uri = Uri.parse(url);
return uri.isAbsolute() ? uri : Uri.parse(AUTHORITY + url);
}
public static Uri constructUri(File file) {
Uri uri = Uri.parse(file.getAbsolutePath());
return uri.isAbsolute() ? uri : Uri.parse(AUTHORITY
+ file.getAbsolutePath());
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
File file = new File(uri.getPath());
ParcelFileDescriptor parcel = ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_READ_ONLY);
return parcel;
}
#Override
public boolean onCreate() {
return true;
}
#Override
public int delete(Uri uri, String s, String[] as) {
throw new UnsupportedOperationException(
"Not supported by this provider");
}
#Override
public String getType(Uri uri) {
return "image/jpeg";
}
#Override
public Uri insert(Uri uri, ContentValues contentvalues) {
throw new UnsupportedOperationException(
"Not supported by this provider");
}
#Override
public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) {
throw new UnsupportedOperationException(
"Not supported by this provider");
}
#Override
public int update(Uri uri, ContentValues contentvalues, String s,
String[] as) {
throw new UnsupportedOperationException(
"Not supported by this provider");
}
}
Then you can call
Uri uri = FileContentProvider.constructUri(file);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(uri,"image/*");
startActivity(intent);
This is a strange workaround but I think it has something to do with how android opens images using a URI. Their openFile(Uri uri, String mode) method is wrong / broken / can't resolve the URI properly.. I'm not really 100% sure though but I found this workaround to be effective.
don't forget to register to provider in the manifest
How could i run the android method that extract the contact list in a vcf format?
Is there an intent that can directly call this action?
thx
François
This may be helpful to you. Try this with your need -
package com.vcard;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.View;
public class VCardActivity extends Activity
{
Cursor cursor;
ArrayList<String> vCard ;
String vfile;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.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.
* */
getVcardString();
}
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);
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);
AssetFileDescriptor fd;
try {
fd = this.getContentResolver().openAssetFileDescriptor(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 = fd.createInputStream();
byte[] buf = new byte[(int) fd.getDeclaredLength()];
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();
}
}
}
Here's how to extract to VCF file and share it via an intent, with the option of sharing a single contact if you wish:
#WorkerThread
#Nullable
public static Intent getContactShareIntent(#NonNull Context context, #Nullable String contactId, #NonNull String filePath) {
final ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = TextUtils.isEmpty(contactId) ? contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null) :
contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, Data.CONTACT_ID + "=?", new String[]{contactId}, null);
if (cursor == null || !cursor.moveToFirst())
return null;
final File file = new File(filePath);
file.delete();
do {
String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
AssetFileDescriptor fd;
try {
fd = contentResolver.openAssetFileDescriptor(uri, "r");
if (fd == null)
return null;
FileInputStream fis = fd.createInputStream();
IOUtils.copy(fis, new FileOutputStream(filePath, false));
cursor.moveToNext();
} catch (Exception e1) {
e1.printStackTrace();
}
} while (cursor.moveToNext());
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
intent.setType("*/*");
return intent;
}
You can do this manually in the contacts App. But there is no Intent for that. If you want your App to have such an export you unfortunately have to write it yourself or use code from here.vcardio
This has changed as of Sept., 2016. You can now export your contacts to a VCF file using the 'People' app: select 'Import/export' in the menu, then one of the export items. You'll still have to get the file off your phone but that's easy enough via ADB (or maybe email.)