Reputation: 5160
I know a question almost like this was asked several times but that problem is different. I need to write data to the external storage. I know I need to ask for permissions at runtime on Android 6. All this works fine so far. Just one thing is weird. The granted permission only seems to work the second time I start the app.
My example looks like this:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_WRITE_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Permission granted!");
write();
} else {
Log.d(TAG, "No permission granted!");
}
}
}
}
@Override
public void onClick(View v) {
boolean hasPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
Log.d(TAG, "Has no permission! Ask!");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_STORAGE);
} else {
Log.d(TAG, "Permission already given!");
write();
}
}
private void write(){
Log.d(TAG, "Trying to write");
// Get the directory for the user's public pictures directory.
File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
if (! root.exists() && !root.mkdirs()) {
Log.e(TAG, "Directory not created");
return;
}
File testFile = new File(root, "TEST.tmp");
FileWriter writer;
try {
StringBuilder sb = new StringBuilder();
sb.append("TEST TEST TEST");
writer = new FileWriter(testFile, false);
writer.append(sb.toString());
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "Write successful");
}
Pressing the button calls the onClick()
which is checking for permissions. If granted it calls the write()
method - if not it asks for permission.
So when pressing the button first time, the permission popup opens, I click "yes" and assumed, it would write my test file. Still, I get the following error message and the file or even the directory was not created:
D/LOG: Has no permission! Ask!
D/LOG: Permission granted!
D/LOG: Trying to write
E/LOG: Directory not created
If I click again (with already given permission) it only shows
D/LOG: Permission already given!
D/LOG: Trying to write
E/LOG: Directory not created
In fact neither the directory nor the file exist yet. So I close the app and start it again and press the button. The console shows this:
D/LOG: Permission already given!
D/LOG: Trying to write
D/LOG: Write successful
Voila, now the directory and file exist.
So why does it only work the second time I start the app? It appears the permissions are only refreshed on app start. Any ideas?
---- EDIT ----
Related to the comment, I separated exists()
and mkdirs()
.
Still the method looks like this:
private void write(){
Log.d(TAG, "Trying to write");
// Get the directory for the user's public pictures directory.
File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
if (! root.exists()){
if(!root.mkdirs()) {
Log.e(TAG, "Directory not created");
return;
} else {
Log.e(TAG, "Directory created");
}
}
...
Still, first time the app starts I get Directory not created. Next time I start the app, the directory was created. So this doesn't seem to be the problem.
Also, I added a method checking if Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
exists. This one is true, even at first start. Whats failing is the mkdirs()
for my sub folder.
Upvotes: 4
Views: 1054
Reputation: 5160
As posted here: https://stackoverflow.com/a/37135078/1565635 I believe I found the solution - or at least an explanation.
It turns out this seems to be a bigger issue. Changing the permission to write to the external storage changes the Linux GID for this process. In order to change the ID the process has to be restarted. Next time the app opens, the new groupID is set and the permission is granted. That leads to the conclusion that this is not a bug but in fact a bigger issue with Linux and Android.
I "solved" this by asking for permission the first time the app is executed and restarting it when the permission is given like this:
PackageManager packageManager = getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
ComponentName componentName = intent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
startActivity(mainIntent);
System.exit(0);
A solution I didn't try was to create a service running in the background (thus having another process id) and giving it the permission. That way only the service needs to be restarted but not the complete app. On the down side this might make more work for communication between the processes. If I understand it right, a content provider might work, too but also means more work.
--- EDIT ---
The user M66B (https://stackoverflow.com/a/32473449/1565635) found a list of the related gids. Further information can be found here: https://android.googlesource.com/platform/frameworks/base/+/master/data/etc/platform.xml
Upvotes: 1
Reputation: 1591
Try this code:-
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_WRITE_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Permission granted!");
write();
} else {
Log.d(TAG, "No permission granted!");
}
}
}
}
@Override
public void onClick(View v) {
File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
dircheck(root);
filecheck(new File(root, "TEST.tmp"));
boolean hasPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
Log.d(TAG, "Has no permission! Ask!");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_STORAGE);
} else {
Log.d(TAG, "Permission already given!");
write();
}
}
private void dircheck(File file) {
if (!file.exists()) {
file.mkdirs();
}
}
private void filecheck(File file){
if(!file.exists()){
file.createNewFile();
}
}
private void write(){
File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
File testFile = new File(root, "TEST.tmp");
FileWriter writer;
try {
StringBuilder sb = new StringBuilder();
sb.append("TEST TEST TEST");
writer = new FileWriter(testFile, false);
writer.append(sb.toString());
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "Write successful");
}
Upvotes: 0