I have an android app that writes files to a directory in internal storage, but it only does that correctly for certain API's. It works fine on my phone which uses Android 5.1 (API 22). And on the Nexus 5 emulator (API 21). However, in most tablets with API >=23 it can't get the directory. It writes the file in a separate activity and puts them in a listView for display in this activity. Whenever this activity loads, it doesn't get any files because the directory 'path' doesn't exist. Yes, I have all the read/write external storage permissions in the manifest. I've included the full code for the activity if anyone really needs to see it, but the part that matters here is only down to the last log tag.
public class ListResults extends Activity {
int data_block = 100;
ArrayList<String> arraylist;
String path_string = Environment.getExternalStorageDirectory().getAbsolutePath()+"/TrafficCounter";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_results);
ListView listView1 = (ListView) findViewById(R.id.list);
File path = new File(path_string);
path.mkdirs();
String dir = "" + path;
Log.d("TAG","Path exists: " + path.exists());
Log.d("TAG",String.valueOf(path.mkdirs()));
Log.d("TAG",path.toString());
File f = new File(dir);
String[] fileList = f.list();
Log.d("TAG", Arrays.deepToString(fileList));
//////////////////////////////Rest of Activity (Not Relevant)///////////////////////////////////
arraylist= new ArrayList<String>();
if(fileList!=null){
for(int i=0;i<fileList.length;i++)
{
arraylist.add(fileList[i]);
}}
Collections.sort(arraylist);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arraylist);
listView1.setAdapter(adapter);
listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final String filename = ((TextView) view).getText().toString();
//Creating dialog for choosing what to do with files
final Dialog dialog = new Dialog(ListResults.this);
dialog.setContentView(R.layout.file_options_menu);
dialog.show();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
TextView nameDisplay = (TextView)dialog.findViewById(R.id.file_name);
nameDisplay.setText(filename);
//Defining all buttons within the dialog
Button viewButton = (Button)dialog.findViewById(R.id.view_button);
Button shareButton = (Button)dialog.findViewById(R.id.share_button);
Button deleteButton = (Button)dialog.findViewById(R.id.delete_button);
Button cancelButton = (Button)dialog.findViewById(R.id.cancel_button);
//View option
viewButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
File path = new File(path_string);
File file = new File(path + "/" + filename);
String[] loadText = Load(file);
String finalString = "";
for (int i = 0; i < loadText.length; i++) {
finalString += loadText[i] + System.getProperty("line.separator");
}
// Launching new Activity on selecting single List Item
Intent i = new Intent(getApplicationContext(), SingleListItem.class);
// sending data to new activity
i.putExtra("product", finalString);
i.putExtra("filename export", filename);
dialog.cancel();
startActivity(i);
finish();
}
});
//Upload option from within the dialog
shareButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
File path = new File(path_string);
File file = new File(path + "/" + filename);
Uri uri = Uri.fromFile(file);
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent,
getResources().getText(R.string.chooser_text)));
dialog.cancel();
}
});
//Delete button function
deleteButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
File path = new File(path_string);
File file = new File(path,filename);
file.delete();
Toast.makeText(getApplicationContext(), "File Deleted", Toast.LENGTH_SHORT).show();
dialog.cancel();
Intent intent = getIntent();
finish();
startActivity(intent);
}
});
//Cancel option from dialog
cancelButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
dialog.cancel();
}
});
}
});
}
public static String[] Load(File file)
{
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
}
catch (FileNotFoundException e) {e.printStackTrace();}
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String test;
int anzahl=0;
try
{
while ((test=br.readLine()) != null)
{
anzahl++;
}
}
catch (IOException e) {e.printStackTrace();}
try
{
fis.getChannel().position(0);
}
catch (IOException e) {e.printStackTrace();}
String[] array = new String[anzahl];
String line;
int i = 0;
try
{
while((line=br.readLine())!=null)
{
array[i] = line;
i++;
}
}
catch (IOException e) {e.printStackTrace();}
return array;
}
public void onRestart(View view) {
Intent restart = new Intent(this, MainActivity.class);
startActivity(restart);
}
}
I included the log tags I get for each of the following tests. First one is whether or not the directory exists, second line is if mkdirs(); was used, third is the actual address, and fourth is the actual array of files in the directory. For the Nexus 5 Emulator (API 21, works):
D/TAG: Path exists: true
D/TAG: false
D/TAG: /storage/sdcard/TrafficCounter
D/TAG: [test.txt]
For my actual phone (API 22, works):
D/TAG: Path exists: true
D/TAG: false
D/TAG: /storage/emulated/0/TrafficCounter
D/TAG: [Test.txt]
For Nexus 7 and Nexus S Emulators (API 23, doesn't work):
D/TAG: Path exists: false
D/TAG: false
D/TAG: /storage/emulated/0/TrafficCounter
D/TAG: null
Does anyone know how to properly get the directory for the higher API's? Or am I completely missing something else?