0

I select file using startActivityForResult, which open deafult File Manager, and it should return path of my selected file. After I'm trying to copy that file in my internal storage and I'm trying to open that file using another app, i.e. opening a .jpg with Gallery, .pdf with Acrobat... But the code don't work

This is my code:

package com.example.francesco.pdf_viewer;

import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.net.URI;


import static android.util.JsonToken.NULL;
import static java.net.Proxy.Type.HTTP;

public class MainActivity extends AppCompatActivity {

static final int SELECT_FILE_REQUEST = 2;
private Uri uri;
Button clickButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    clickButton = (Button) findViewById(R.id.clickPath);

    clickButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            File f = new File(uri.getPath());
            Uri u = Uri.fromFile(f);
            Intent filePathIntent = new Intent(Intent.ACTION_VIEW, u);
            startActivity(filePathIntent);
        }
    });

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            selectFile();
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (requestCode == SELECT_FILE_REQUEST) {
        if (resultCode == RESULT_OK) {
            Uri fileUri = data.getData();
            //String filename = fileUri.getPath();
            uri = fileUri;
            Toast.makeText(getApplicationContext(), fileUri.toString(), Toast.LENGTH_LONG).show();
        }
    }

}


private void selectFile() {
    Intent selectFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
    selectFileIntent.setType("*/*");
    selectFileIntent.addCategory(Intent.CATEGORY_OPENABLE);

    try {
        startActivityForResult(Intent.createChooser(selectFileIntent, "Select a File"), SELECT_FILE_REQUEST);

    } catch (android.content.ActivityNotFoundException e) {
        Toast.makeText(this, "Please install a File Manager", Toast.LENGTH_SHORT).show();
    }


}


}

Thank you, Sorry for English

EDIT: The uri, that i get from startActivityForResult, is this : "content:://com.android.providers.downloads.documents/document/10"

But the original path of the file, that i download, is this: /storage/emulated/0/Download/1/android-n-n.jpg

2 Answers2

0

If your targetSdkVersion is 24 or higher, we have to use FileProvider class to give access to the particular file or folder to make them accessible for other apps.

Check this answerlink

Community
  • 1
  • 1
Dishonered
  • 8,449
  • 9
  • 37
  • 50
0

As of Android N, in order to work around this issue, you need to use the FileProvider API.

There are 3 main steps here.

Step 1: Manifest Entry

<manifest ...>
    <application ...>
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>
</manifest>

Step 2: Create XML file res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Step 3: Code changes

File file = ...;
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
// Old Approach
    install.setDataAndType(Uri.fromFile(file), mimeType);
// End Old approach
// New Approach
    Uri apkURI = FileProvider.getUriForFile(
                             context, 
                             context.getApplicationContext()
                             .getPackageName() + ".provider", file);
    install.setDataAndType(apkURI, mimeType);
    install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// End New Approach
    context.startActivity(install);

Read detailed article here about this issue.

To copy file in internal storage:

Create a directory in android internal storage using following lines and give it as destination file directory:

File directory = getDir("FileDir", Context.MODE_PRIVATE);

Copy file from source(Download directory) to destination(internal storage) using below function.

private boolean copyFile(File src,File dst)throws IOException{
    if(src.getAbsolutePath().toString().equals(dst.getAbsolutePath().toString())){

        return true;

    }else{
        InputStream is=new FileInputStream(src);
        OutputStream os=new FileOutputStream(dst);
        byte[] buff=new byte[1024];
        int len;
        while((len=is.read(buff))>0){
            os.write(buff,0,len);
        }
        is.close();
        os.close();
    }
    return true;
}
Priyank Patel
  • 12,244
  • 8
  • 65
  • 85
  • This code works and I open correctly "file", but I want to take the file in directory "Download" and it copy in internal storage of my app – Francesco.D.B. Apr 25 '17 at 15:13
  • @Francesco.D.B. checkout my updated answer to copy your selected file from external to internal storage. – Priyank Patel Apr 26 '17 at 05:05
  • I try your code but the file .png that I try to open don't show the correct image but it shows a black image with the text "couldn't load the photo" e the path is wrog – Francesco.D.B. Apr 28 '17 at 20:38
  • the correct image path is :/storage/emulated/0/Download/1android-n-n.jpg, but the path file, that intente open, is content://come.example.francesco.pdf_viewer.provider/external:files/Download/1android_n.png – Francesco.D.B. Apr 28 '17 at 20:41