Carlos Hernández Carlos Hernández - 2 months ago 6
Android Question

I can not see external files in directory with AlertDialog in Android 6.0?

When I run my app in android 5.1 I have not problem seeing the root file in my AlertDialog, but when I run in 6.0 does not show me anything, how to fix it? Here I show differences in images.

In android 5.1

In android 6.0

SimpleFileDialog.java

public class SimpleFileDialog
{
private int FileOpen = 0;
private int FileSave = 1;
private int FolderChoose = 2;
private int Select_type = FileSave;
private String m_sdcardDirectory = "";
private Context m_context;
private TextView m_titleView1;
private TextView m_titleView;
public String Default_File_Name = "default.txt";
private String Selected_File_Name = Default_File_Name;
private EditText input_text;

private String m_dir = "";
private List<String> m_subdirs = null;
private SimpleFileDialogListener m_SimpleFileDialogListener = null;
private ArrayAdapter<String> m_listAdapter = null;

//////////////////////////////////////////////////////
// Callback interface for selected directory
//////////////////////////////////////////////////////
public interface SimpleFileDialogListener
{
public void onChosenDir(String chosenDir);
}

public SimpleFileDialog(Context context, String file_select_type, SimpleFileDialogListener SimpleFileDialogListener)
{
if (file_select_type.equals("FileOpen")) Select_type = FileOpen;
else if (file_select_type.equals("FileSave")) Select_type = FileSave;
else if (file_select_type.equals("FolderChoose")) Select_type = FolderChoose;
else Select_type = FileOpen;

m_context = context;
m_sdcardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
m_SimpleFileDialogListener = SimpleFileDialogListener;

try
{
m_sdcardDirectory = new File(m_sdcardDirectory).getCanonicalPath();
}
catch (IOException ioe)
{
}
}

///////////////////////////////////////////////////////////////////////
// chooseFile_or_Dir() - load directory chooser dialog for initial
// default sdcard directory
///////////////////////////////////////////////////////////////////////
public void chooseFile_or_Dir()
{
// Initial directory is sdcard directory
if (m_dir.equals("")) chooseFile_or_Dir(m_sdcardDirectory);
else chooseFile_or_Dir(m_dir);
}

////////////////////////////////////////////////////////////////////////////////
// chooseFile_or_Dir(String dir) - load directory chooser dialog for initial
// input 'dir' directory
////////////////////////////////////////////////////////////////////////////////
public void chooseFile_or_Dir(String dir)
{
File dirFile = new File(dir);
if (! dirFile.exists() || ! dirFile.isDirectory())
{
dir = m_sdcardDirectory;
}

try
{
dir = new File(dir).getCanonicalPath();
}
catch (IOException ioe)
{
return;
}

m_dir = dir;
m_subdirs = getDirectories(dir);

class SimpleFileDialogOnClickListener implements DialogInterface.OnClickListener
{
public void onClick(DialogInterface dialog, int item)
{
String m_dir_old = m_dir;
String sel = "" + ((AlertDialog) dialog).getListView().getAdapter().getItem(item);
if (sel.charAt(sel.length()-1) == '/') sel = sel.substring(0, sel.length()-1);

// Navigate into the sub-directory
if (sel.equals(".."))
{
m_dir = m_dir.substring(0, m_dir.lastIndexOf("/"));
}
else
{
m_dir += "/" + sel;
}
Selected_File_Name = Default_File_Name;

if ((new File(m_dir).isFile())) // If the selection is a regular file
{
m_dir = m_dir_old;
Selected_File_Name = sel;
}

updateDirectory();
}
}

AlertDialog.Builder dialogBuilder = createDirectoryChooserDialog(dir, m_subdirs,
new SimpleFileDialogOnClickListener());

dialogBuilder.setPositiveButton("Aceptar", new OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
// Current directory chosen
// Call registered listener supplied with the chosen directory
if (m_SimpleFileDialogListener != null){
{
if (Select_type == FileOpen || Select_type == FileSave)
{
Selected_File_Name= input_text.getText() +"";
m_SimpleFileDialogListener.onChosenDir(m_dir + "/" + Selected_File_Name);}
else
{
m_SimpleFileDialogListener.onChosenDir(m_dir);
}
}
}
}
}).setNegativeButton("Cancelar", null);

final AlertDialog dirsDialog = dialogBuilder.create();

// Show directory chooser dialog
dirsDialog.show();
}

private boolean createSubDir(String newDir)
{
File newDirFile = new File(newDir);
if (! newDirFile.exists() ) return newDirFile.mkdir();
else return false;
}

private List<String> getDirectories(String dir)
{
List<String> dirs = new ArrayList<String>();
try
{
File dirFile = new File(dir);

// if directory is not the base sd card directory add ".." for going up one directory
if (! m_dir.equals(m_sdcardDirectory) ) dirs.add("..");

if (! dirFile.exists() || ! dirFile.isDirectory())
{
return dirs;
}

for (File file : dirFile.listFiles())
{
if ( file.isDirectory())
{
// Add "/" to directory names to identify them in the list
dirs.add( file.getName() + "/" );
}
else if (Select_type == FileSave || Select_type == FileOpen)
{
// Add file names to the list if we are doing a file save or file open operation
dirs.add( file.getName() );
}
}
}
catch (Exception e) {}

Collections.sort(dirs, new Comparator<String>()
{
public int compare(String o1, String o2)
{
return o1.compareTo(o2);
}
});
return dirs;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
////// START DIALOG DEFINITION //////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
private AlertDialog.Builder createDirectoryChooserDialog(String title, List<String> listItems,
DialogInterface.OnClickListener onClickListener)
{
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(m_context);
////////////////////////////////////////////////
// Create title text showing file select type //
////////////////////////////////////////////////
m_titleView1 = new TextView(m_context);
m_titleView1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
//m_titleView1.setTextAppearance(m_context, android.R.style.TextAppearance_Large);
//m_titleView1.setTextColor( m_context.getResources().getColor(android.R.color.black) );

if (Select_type == FileOpen ) m_titleView1.setText("Open:");
if (Select_type == FileSave ) m_titleView1.setText("Save As:");
if (Select_type == FolderChoose) m_titleView1.setText("Folder Select:");

//need to make this a variable Save as, Open, Select Directory
m_titleView1.setGravity(Gravity.CENTER_VERTICAL);
// m_titleView1.setBackgroundColor(-12303292); // dark gray -12303292
m_titleView1.setTextColor( m_context.getResources().getColor(android.R.color.white) );

// Create custom view for AlertDialog title
LinearLayout titleLayout1 = new LinearLayout(m_context);
titleLayout1.setOrientation(LinearLayout.VERTICAL);
titleLayout1.addView(m_titleView1);


if (Select_type == FolderChoose || Select_type == FileSave)
{
///////////////////////////////
// Create New Folder Button //
///////////////////////////////
Button newDirButton = new Button(m_context);
newDirButton.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
newDirButton.setText("New Folder");
newDirButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
final EditText input = new EditText(m_context);

// Show new folder name input dialog
new AlertDialog.Builder(m_context).
setTitle("New Folder Name").
setView(input).setPositiveButton("Aceptar", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
Editable newDir = input.getText();
String newDirName = newDir.toString();
// Create new directory
if ( createSubDir(m_dir + "/" + newDirName) )
{
// Navigate into the new directory
m_dir += "/" + newDirName;
updateDirectory();
}
else
{
Toast.makeText( m_context, "Failed to create '"
+ newDirName + "' folder", Toast.LENGTH_SHORT).show();
}
}
}).setNegativeButton("Cancelar", null).show();
}
}
);
titleLayout1.addView(newDirButton);
}

/////////////////////////////////////////////////////
// Create View with folder path and entry text box //
/////////////////////////////////////////////////////
LinearLayout titleLayout = new LinearLayout(m_context);
titleLayout.setOrientation(LinearLayout.VERTICAL);

m_titleView = new TextView(m_context);
m_titleView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
// m_titleView.setBackgroundColor(-12303292); // dark gray -12303292
m_titleView.setTextColor( m_context.getResources().getColor(android.R.color.white) );
m_titleView.setGravity(Gravity.CENTER_VERTICAL);
m_titleView.setText(title);

titleLayout.addView(m_titleView);

if (Select_type == FileOpen || Select_type == FileSave)
{
input_text = new EditText(m_context);
input_text.setText(Default_File_Name);
titleLayout.addView(input_text);
}
//////////////////////////////////////////
// Set Views and Finish Dialog builder //
//////////////////////////////////////////
dialogBuilder.setView(titleLayout);
dialogBuilder.setCustomTitle(titleLayout1);
m_listAdapter = createListAdapter(listItems);
dialogBuilder.setSingleChoiceItems(m_listAdapter, -1, onClickListener);
dialogBuilder.setCancelable(false);
return dialogBuilder;
}

private void updateDirectory()
{
m_subdirs.clear();
m_subdirs.addAll( getDirectories(m_dir) );
m_titleView.setText(m_dir);
m_listAdapter.notifyDataSetChanged();
//#scorch
if (Select_type == FileSave || Select_type == FileOpen)
{
input_text.setText(Selected_File_Name);
}
}

private ArrayAdapter<String> createListAdapter(List<String> items)
{
return new ArrayAdapter<String>(m_context, android.R.layout.select_dialog_item, android.R.id.text1, items)
{
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = super.getView(position, convertView, parent);
if (v instanceof TextView)
{
// Enable list item (directory) text wrapping
TextView tv = (TextView) v;
tv.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
tv.setEllipsize(null);
}
return v;
}
};
}


MainActivity.java

public class MainActivity extends Activity implements
AdapterContactos.customButtonListener {

TextView contenido;
ListView lista;
Button cargar,agregarTodos;

AdapterContactos adapter;
ArrayList<Contact> contactos;
ArrayList<Contact> contactos2;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

contenido = (TextView)findViewById(R.id.tvcontenido);
lista = (ListView)findViewById(R.id.listview);
cargar = (Button)findViewById(R.id.btrecuperar);
agregarTodos = (Button)findViewById(R.id.btagregartodos);



contactos = new ArrayList<>();
contactos2 = new ArrayList<>();
cargarDataBase();

if(contactos2.isEmpty()){
agregarTodos.setEnabled(false);
}

cargar.setOnClickListener(new Button.OnClickListener(){

String m_chosen;
@Override
public void onClick(View v) {
/////////////////////////////////////////////////////////////////////////////////////////////////
//Create FileOpenDialog and register a callback
/////////////////////////////////////////////////////////////////////////////////////////////////
SimpleFileDialog FileOpenDialog = new SimpleFileDialog(MainActivity.this, "FileOpen",
new SimpleFileDialog.SimpleFileDialogListener()
{
@Override
public void onChosenDir(String chosenDir)
{
// The code in this function will be executed when the dialog OK button is pushed
m_chosen = chosenDir;

contenido.setText(m_chosen);
Toast.makeText(MainActivity.this, "Archivo escogido File: " +
m_chosen, Toast.LENGTH_LONG).show();
}
});

//You can change the default filename using the public variable "Default_File_Name"
FileOpenDialog.Default_File_Name = "";
FileOpenDialog.chooseFile_or_Dir();

/////////////////////////////////////////////////////////////////////////////////////////////////

}
});
}


My Gradle

android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "com.example.carlos.lectura"
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
}

Answer

One of the permissions required for Android 6.0 is WRITE_EXTERNAL_STORAGE (implicit READ_EXTERNAL_STORAGE) :

you can request the permission before the reading for the external storage calling this method:

private void checkExternalStoragePermission() {
    int permissionCheck = ContextCompat.checkSelfPermission(
            this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        Log.i("Permission", "We dont have permission.");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 225);
    } else {
        Log.i("Permission", "You already have permission!");
    }
}

In fact you can validate the calling of the method for request permissions only un OS Android 6.0+ :

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
    //Check permissions for Android 6.0+
     checkExternalStoragePermission();
}