I have to share a url on android default but i want a response if url is being shared or just intent is closed. I am using on activity result but when i share with gmail it return 0(CANCELED) same when i close the intent.I need this to set text shared on a text view.Here is my code.
public void executeShareLinkClick() {
Intent intentShare = new Intent(ACTION_SEND);
intentShare.setType("text/plain");
viewModel.isLinkSharedOpen.set(true);
intentShare.putExtra(Intent.EXTRA_TEXT,"My Text of the message goes here ... write anything what you want");
startActivityForResult(Intent.createChooser(intentShare, "Shared the text ..."),111);
}
public void onActivityResult(int requestCode, int resultCode, #Nullable #org.jetbrains.annotations.Nullable Intent data) {
if (resultCode==RESULT_OK){
viewModel.isLinkShared.set(true);
}else{
viewModel.isLinkShared.set(false);
}
viewModel.isLinkSharedOpen.set(false);
}
Sorry, but what you want is not an option. ACTION_SEND does not support a result, and apps do not have to indicate whether or not the user sent your content.
The closest thing you can do is to add EXTRA_CHOSEN_COMPONENT_INTENT_SENDER to the Intent returned by createChooser(). Through that, you can find out if the user chose something in that chooser. However:
I don't think you find out if the user chose nothing
It still does not indicate that the user actually used the chosen app to send your content
if(getIntent().getData() != null) {
Uri fileUri = getIntent().getData();
File file = new File(fileUri);
}
// for multiple files
if(getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE) && getIntent().getClipData() != null) {
int count = getIntent().getClipData().getItemCount();
int currentUri = 0;
while(currentUri < count) {
Uri fileUri = getIntent().getClipData().getItemAt(currentUri).getUri();
File file = new File(fileUri);
currentUri = currentUri + 1;
}
}
Related
I am developing an app for filling pdf forms, I am saving the pdf to the internal storage and then sharing it using the intent ACTION_CREATE_DOCUMENT. This intent returns a URI which i then copy my local pdf into.
All this works fine however the intent opens a file explorer popup so that the user can choose where to save the pdf, and here in lies the problem, when the user presses SAVE; the app creates a 0b file in that location (as it should), but then it reopens the file explorer prompting the user to SAVE again, this happens two or three times and then it finally close for real at which point the pdf data overwrites the latest of the now numerous 0b files.
public int WRITE_REQUEST_CODE=45;
...
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void buttonExport(View view) {
Toast.makeText(this, "Exporting - This will take around 1min", Toast.LENGTH_LONG).show();
// Template of PDF with acrofields (template.pdf).
// TRY to open the pdf stored in the raw res directory
// then convert it to a file object by copying it
try {
//
InputStream inputStream =null;
if (template.equals("crfminortemplate")){
inputStream = getResources().openRawResource(R.raw.crfminorpdftemplat);
}
else if (template.equals("crfmajortemplate")){
inputStream = getResources().openRawResource(R.raw.crfmajorpdftemplat);
}
File tempFile = new File(getFilesDir(),template);
//
copyFile(inputStream, new FileOutputStream(tempFile));
// Now Questions res is tempFile ..
} catch (IOException e) {
throw new RuntimeException("Can't create temp file ", e);
}
try {
PDFManipulation.fillPDF(view, template, fileName, Answers);
} catch (IOException e) {
e.printStackTrace();
}
catch (NullPointerException e)
{
e.printStackTrace();
}
Toast.makeText(this, "Export Complete - save to drive or email", Toast.LENGTH_LONG).show();
sharePDF(getFilesDir()+"/"+fileName+".pdf");
}
private void sharePDF(String PDFPPath) {
Uri path = FileProvider.getUriForFile(this, "com.example.cst_app_v3", new File(getFilesDir(),fileName+".pdf"));
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, "Sent from CST App Android " + PDFPPath);
shareIntent.putExtra(Intent.EXTRA_STREAM, path);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setType("application/pdf");
startActivityForResult(shareIntent,0);
Intent saveIntent = new Intent();
saveIntent.setAction(Intent.ACTION_CREATE_DOCUMENT);
saveIntent.putExtra(Intent.EXTRA_TITLE,fileName+".pdf");
saveIntent.addCategory(Intent.CATEGORY_OPENABLE);
saveIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
saveIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
saveIntent.setType("application/pdf");
startActivityForResult(saveIntent,WRITE_REQUEST_CODE);
Intent chooserIntent = Intent.createChooser(shareIntent, "Share or Save ...");
Intent[]arrayofintent = {saveIntent};
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,arrayofintent);
startActivityForResult(chooserIntent,0);
startActivity(chooserIntent);
Log.d("Alert",path.getAuthority()+" "+ path.getPath());
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (resultCode == RESULT_OK && requestCode == WRITE_REQUEST_CODE) {
//DO THE COPY PASTE FROM LOCAL to THE URI data
}
}
Again
I want the user to start the save intent and have the file selector popup once let the user name the file and choose the save location, press save and then return to my the my app where the pdf is copied to the location they specified
if anyone knows/has experienced this issue or thinks they know what might be happening it would be great to hear from you.
Every time you call startActivityForResult or startActivity it will start a new Activity.
So I count 4 of these in your example code but with only 2 calls that will actually return a result that would cause a file to be written.
To fix this just remove all the startActivityForResult or startActivity EXCEPT for the third one which you change to startActivityForResult(chooserIntent,WRITE_REQUEST_CODE);
This works (was tested) BUT provides a very bad UI experience as you have to know to select the Files App to save the document.
It would be much better to split these to different types of action in to separate menu items, Buttons, Floating Action Buttons, or however you getting the user to "Share or Save" as you can provide a better UI than the Intent chooser.
I am trying to fetch a file this way:
final Intent chooseFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
String[] mimetypes = {"application/pdf"};
chooseFileIntent.setType("*/*");
chooseFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
if (chooseFileIntent.resolveActivity(activity
.getApplicationContext().getPackageManager()) != null) {
chooseFileIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
activity.startActivityForResult(chooseFileIntent, Uploader.PDF);
}
Then in onActivityResult :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
According to many threads I'm supposed to fetch the file name from the intent with data.getData().getPath(), the file name I'm expecting is my_file.pdf, but instead I'm getting this :
/document/acc=1;doc=28
So what to do? Thanks for your help.
I am trying to fetch a file
Not with that code. That code is asking the user to pick a piece of content. This may or may not be a file.
According to many threads I'm supposed to fetch the file name from the intent with data.getData().getPath()
That was never correct, though it tended to work on older versions of Android.
So what to do?
Well, that depends.
If you wish to only accept files, integrate a file chooser library instead of using ACTION_GET_CONTENT. (UPDATE 2019-04-06: since Android Q is banning most filesystem access, this solution is no longer practical)
If you are willing to allow the user to pick a piece of content using ACTION_GET_CONTENT, please understand that it does not have to be a file and it does not have to have something that resembles a filename. The closest that you will get:
If getScheme() of the Uri returns file, your original algorithm will work
If getScheme() of the Uri returns content, use DocumentFile.fromSingleUri() to create a DocumentFile, then call getName() on that DocumentFile — this should return a "display name" which should be recognizable to the user
To get the real name and to avoid getting a name that looks like "image: 4431" or even just a number, you can write code as recommended by CommonsWare.
The following is an example of a code that selects a single pdf file, prints its name and path to the log, and then sends the file by email using its uri.
private static final int FILEPICKER_RESULT_CODE = 1;
private static final int SEND_EMAIL_RESULT_CODE = 2;
private Uri fileUri;
private void chooseFile() {
Intent fileChooser = new Intent(Intent.ACTION_GET_CONTENT);
fileChooser.setType("application/pdf");
startActivityForResult(Intent.createChooser(fileChooser, "Choose one pdf file"), FILEPICKER_RESULT_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILEPICKER_RESULT_CODE) {
if (resultCode == RESULT_OK) {
fileUri = data != null ? data.getData() : null;
if (fileUri != null) {
DocumentFile d = DocumentFile.fromSingleUri(this, fileUri);
if (d != null) {
Log.d("TAG", "file name: " + d.getName());
Log.d("TAG", "file path: " + d.getUri().getPath());
sendEmail(fileUri);
}
}
}
}
}
private void sendEmail(Uri path) {
String email = "example#gmail.com";
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType("application/octet-stream");
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "PDF file");
String[] to = { email };
intent.putExtra(Intent.EXTRA_EMAIL, to);
intent.putExtra(Intent.EXTRA_TEXT, "This is the pdf file...");
intent.putExtra(Intent.EXTRA_STREAM, path);
startActivityForResult(Intent.createChooser(intent, "Send mail..."), SEND_EMAIL_RESULT_CODE);
}
hope it helps.
I can't get the normal taken picture by my phone in java. Everything is working while I choose picture from the gallery which is screenshot but when It's normal taken picture it's not returning anything. I will give you some parts of the code where u can see how I'm getting picture.
#Override
public void onActivityResult(int reqCode, int resultCode, final Intent data) {
super.onActivityResult(reqCode, resultCode, data);
if (reqCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) {
final Uri imageUri = data.getData();
final String path = getPath(getActivity(), imageUri);
if (path != null) {
try {
File f1 = new File(path);
final AsyncHttpClient client = new AsyncHttpClient(true, 80, 443);
client.addHeader("accept", "application/json");
final RequestParams params = new RequestParams();
params.put("id", id);
params.put("token", token);
params.put("avatar", f1);
And also this
add_avatar.setOnClickListener(new View.OnClickListener() {
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onClick(View view) {
// filePickUtils.requestImageGallery(STORAGE_PERMISSION_IMAGE, true, true);
if (getActivity().checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(
android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
// Explain to the user why we need to read the contacts
}
requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
1);
// MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
// app-defined int constant that should be quite unique
return;
}
if (getActivity().checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// Explain to the user why we need to read the contacts
}
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
// MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
// app-defined int constant that should be quite unique
return;
}
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
photoPickerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
photoPickerIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, PICK_IMAGE);
}
});
What would you suggest?
Thanks for your help
Given that you only need to read the image, and upload the data to your backend server, I'd suggest if you use Intent.ACTION_GET_CONTENT instead of Intent.ACTION_PICK.
Why
Your problem might related to what Intent.ACTION_PICK needs to have. The documentation stated:
Input: getData() is URI containing a directory of data (vnd.android.cursor.dir/*) from which to pick an item.
So it means, if you want to use Intent.ACTION_PICK, you need to provide the directory of the data.
Meanwhile if you use Intent.ACTION_GET_CONTENT, you can just set the MIME type of the file that you want to search (just as what you are doing now), and use Context.startActivity(intent).
Additional note from the documentation that you might want to read:
Input: getType() is the desired MIME type to retrieve. Note that no URI is supplied in the intent, as there are no constraints on where the returned data originally comes from. You may also include the CATEGORY_OPENABLE if you can only accept data that can be opened as a stream. You may use EXTRA_LOCAL_ONLY to limit content selection to local data. You may use EXTRA_ALLOW_MULTIPLE to allow the user to select multiple items.
Output: The URI of the item that was picked. This must be a content: URI so that any receiver can access it.
Add a comment here, if you need further information.
Sample Code:
In your activity
private searchImageFile() {
Intent intent = new Intent(Intent.GET_CONTENT);
// Filter to only show results that can be "opened"
intent.addCategory(Intent.CATEGORY_OPENABLE);
// Filter to show only images, using the image MIME data type.
// it would be "*/*".
intent.setType("image/*");
startActivityForResult(intent, READ_REQUEST_CODE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
final Uri imageUri = resultData.getData();
//Do something with your Uri.
}
}
I am a newbie in android app development. I have a simple question. I googled about it but couldn't find any satisfactory answer. My question is :
Can we copy and move images to another folder using startactivityforresult() method. If yes, then how can we pass the position of the selected images we want to move or copy ?
Thanks
In your main activity:
Create new ArrayList to hold selected images:
ArrayList<Model_images> selectedImages = new ArrayList<Model_Images>();
Add all selected images to selectedImages in your adapter's
onClick using:
selectedImages.add(al_images.get(position));
Then once you have the list of selected images, Build the intent and
call the activity:
Intent moveIntent = new Intent(this, MoveActivity.class);
moveIntent.putExtra("selected_images", selectedImages);
startActivityForResult(moveIntent, REQUEST_CODE); // REQUEST_CODE is a unique int value within your app for this intent.
Override onActivityResult to receive the response:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// check if the request code is same as what is passed(REQUEST_CODE)
if(requestCode==REQUEST_CODE)
{
if (resultCode == RESULT_OK){
//The called activity completed successfully.
String message=data.getStringExtra("MESSAGE"); //The message passed along with result
}
}
}
In your MoveActivity activity:
Get the passed ArrayList:
ArrayList<model_Images> selectedImages = new ArrayList<Model_Images>();
if(getIntent().getSerializableExtra("selected_images") != null)
selectedImages = getIntent().getSerializableExtra("selected_images");
Move the images to destination folder:
//Move each selected file to destination
for (Model_Images image : selectedImages{
File sourceImage = image.getFile(); //returns the image File from model class to be moved.
File destinationImage = new File("path/to/destination", "filename.extension");
moveFile(sourceImage, destinationImage);
}
//Method to move the file
private void moveFile(File sourceFile, File destFile) throws IOException {
if (!sourceFile.exists()) {
return;
}
FileChannel source = null;
FileChannel destination = null;
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
if (destination != null && source != null) {
destination.transferFrom(source, 0, source.size());
}
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
source.delete();
}
Set the result to calling activity once done:
// Set result back to the calling activity
Intent intent=new Intent();
intent.putExtra("MESSAGE",message); // Set a message for the calling activity
setResult(RESULT_OK,intent); //RESULT_OK represents success result
finish();//finishing activity
P.S: handling storage permission is not discussed and is required to read/write.
I'm trying to write an app in Android Studio that opens multiple music files and stores their paths. At the moment all I'm doing is loading one file at a time which works without issue. For example - the code below shows my onclicklister for the load button and associated code. Some of the code has been simplified for this example. A user clicks the load button in the app and then uses whatever file manager they have installed to select a file which then passes the Uri back to my app. All well and good. However, is it possible to select multiple files and have them passed back to my app as an array of files? So instead of selecting a single audio file maybe the user selects 5 or 6.
If so how do you do this? Many thanks.
Anyway - what I
final View.OnClickListener mGlobal_OnClickListener = new View.OnClickListener() {
public void onClick(final View v) {
int resID2 = v.getId();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("audio/*");
try {
startActivityForResult(intent,resID2); }
catch (Exception e) {
Toast.makeText(getApplicationContext(), "Please install a file manager",Toast.LENGTH_LONG).show();
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent result) {
if (resultCode == RESULT_OK)
{
Uri data = result.getData();
String thePath = data.getPath();
// Do something with the file path
}
}
You will have to put an extra value to your intent inorder to create a chooser to pick multiple files.
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("audio/*");
chooseFile.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(chooseFile, "Choose a file") , 2);
Note: Above method will work only of API level 18 and above. To support API level < 18 in your app, use some library project like Android Multiple File Selector Dialog.