Unpredictable behavior while saving images into storage - android

TLDR: Why isn't my app asking for runtime permissions despite I have written code for it?
I am saving an image into the storage, on button click by doing something like this:
// Function triggered when save button is pressed
private void saveImage(){
// Asking Runtime permissions for API level 23 and higher
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
finallySave();
} else {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},STORAGE_WRITE_REQUEST_CODE);
}
} else {
// Do not ask permissions in the runtime for API level 22 and lower
finallySave();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_WRITE_REQUEST_CODE) {
if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
finallySave()
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
private void finallySave(){
try {
File outFile = new File(imagesDir, "Abc " + System.currentTimeMillis() + ".png");
FileOutputStream outputStream = new FileOutputStream(outFile);
bitmaps[0].compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.flush();
outputStream.close();
scanFile(outFile, "image/png");
} catch (Exception unused) {
}
}
The problem is, sometimes the image is not saved and the following error is shown:
java.io.FileNotFoundException: /storage/emulated/0/Abc/Abc 1601370822977.png (Permission denied)
I found out that this error is thrown when the application is not asking "storage write" permissions on the runtime. Which is the very origin of the problem that I am facing. My app is not asking for runtime permissions in some cases despite I have written the code for it. Replicating this bug is also very difficult because many times the saving operation is carried out successfully.
I am sure that my code for saving images works fine because sometimes it works (this happens when my app asks for runtime permissions) and sometimes it doesn't.
P.S: I encountered this problem when I had reinstalled my app (after uninstalling).
EDIT: imagesDir is a global variable I am assigning is as follows:
imagesDir = getImageDir(); // in onCreate
private File getImageDir() {
File directory = new File(
Environment.getExternalStorageDirectory() + "/Abc");
if (!directory.exists()) {
if (!directory.mkdirs()) {
Toast.makeText(this, "Could not create directory", Toast.LENGTH_SHORT).show();
return null;
}
}
scanFile(directory, "*/*");
return directory;
}

Related

Android SecurityException accesing content

I've developed an Android app that reads a file from the device, copies it into the app's internal storage and analyzes it.
It has been working OK for almost 100% of my users/devices, but since a couple of months ago, for some specific users/devices is crashing reading the file.
This is how I request permissions.
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mydomain.myapp" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
...
On MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUESTS);
}
}
...
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSIONS_REQUESTS) {
if ((grantResults.length == 0) || (grantResults[0] != PackageManager.PERMISSION_GRANTED)) {
if (ActivityCompat.shouldShowRequestPermissionRationale(ContainerActivity.this, permission.WRITE_EXTERNAL_STORAGE)) {
new Builder(this)
.setCancelable(false)
.setTitle("")
.setMessage(getResources().getString(R.string.REQUEST_WRITE_PERMISSION))
.setPositiveButton(getResources().getString(R.string.TXT_OK_BT), (dialog, which) -> ActivityCompat.requestPermissions(ContainerActivity.this, new String[]{permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUESTS))
.setNegativeButton(getResources().getString(R.string.TXT_DENY_BT), (dialog, which) -> finish())
.show();
} else {
finish();
}
}
}
}
To read the file I'm doing this in my ProcessFileFragment.java file:
private ActivityResultLauncher<Intent> filePickerLauncher;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
createFilePickerLauncher();
...
}
private void createFilePickerLauncher() {
filePickerLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent iData = result.getData();
managePickedFile(iData);
}
});
}
private void goToFilePicker() {
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
} else {
intent = new Intent(Intent.ACTION_GET_CONTENT);
}
intent.setType("*/*");
filePickerLauncher.launch(intent);
}
private void managePickedFile(Intent iData) {
Uri sourceFileUri = iData.getData();
new CopyFileTask(ctxt, sourceFileUri).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private class CopyFileTask extends AsyncTask<Void, Float, String> {
private final WeakReference<Context> ctxtRef;
private final Uri fileUri;
public CopyFileTask(Context context, Uri fileUri) {
this.ctxtRef = new WeakReference<>(context);
this.fileUri = fileUri;
}
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(Void... params) {
String destinationPath = "";
Context ctxt = ctxtRef.get();
if(ctxt != null) {
try {
destinationPath = copyFile(ctxt, fileUri);
} catch (IOException e) {
} catch (IllegalStateException e) {
}
}
return destinationPath;
}
#Override
protected void onProgressUpdate(Float... values) {
}
#Override
protected void onPostExecute(String result) {
// File copied successfully
}
#Override
protected void onCancelled() {
}
}
public static String copyFile(Context ctxt, Uri sourceFileUri) throws IOException {
InputStream in = ctxt.getContentResolver().openInputStream(sourceFileUri);
String destinationPath = ctxt.getFilesDir() + "/" + getUriName(ctxt, sourceFileUri);
OutputStream out = new FileOutputStream(destinationPath);
Log.e("MYAPP", "Copying files from "+sourceFileUri.getPath()+" to "+destinationPath);
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
if (in != null) { in.close(); }
if (out != null){ out.close(); }
return destinationPath;
}
public static String getUriName(Context ctxt, Uri uri) {
String[] projection = { OpenableColumns.DISPLAY_NAME };
Cursor returnCursor = ctxt.getContentResolver().query(uri, projection, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
String name = returnCursor.getString(nameIndex);
returnCursor.close();
return name;
}
The crashes are in this line:
InputStream in = ctxt.getContentResolver().openInputStream(sourceFileUri);
And these are some crashes reading the file:
java.lang.SecurityException: com.android.providers.downloads has no
access to content://media/external_primary/file/1000000454
java.lang.SecurityException: com.samsung.android.providers.media has
no access to content://media/external_primary/file/1000001204
java.lang.SecurityException: com.android.externalstorage has no
access to content://media/4756-1ac1/file/4632
According to Crashlytics, app has crashed 46 times to 5 users with this distribution:
Devices:
54% Samsung Galaxy S22 Ultra
24% Coosea DEMK4119
11% Samsung Galaxy S22
11% Samsung Galaxy S10+
Android OS:
67% Android 12
33% Android 13
I'm testing with different devices, specially with a Samsung Galaxy A51 and I'm having no problems, so it's difficult to know what is happening.
As far as I know, declaring WRITE_EXTERNAL_PERMISSION is not necessary to declare READ_EXTERNAL_PERMISSION, and after reading several posts similar to this I don't have any clue to what could I test.
Any help would be very appreciated.
There's an issue on some Samsung devices and I've seen this happening with my app in production.
A possible fix is to ask your users to do the following:
Go into Settings in your phone and search for "All files access".
Open it and then tap the 3-dot menu in the top-right corner, and tap "Show System".
Then, find and tap "External Storage" and make sure "Allow access to manage all files" is enabled."
Reference: https://issuetracker.google.com/issues/258270138
Due to security reasons Android restricted storage permission.
From Android Documentation
If your app targets Android 11, both the WRITE_EXTERNAL_STORAGE permission and the WRITE_MEDIA_STORAGE privileged permission no longer provide any additional access.
Target Android 11
Now you can't just copy paste thing anywhere you want. Now, the media files should be stored in their respective dirs. For example images should be stored in the Storage > Pictures dir.
No permissions needed if you only access your own media files
On devices that run Android 10 or higher, you don't need any storage-related permissions to access and modify media files that your app owns, including files in the MediaStore.Downloads collection. If you're developing a camera app, for example, you don't need to request storage-related permissions because your app owns the images that you're writing to the media store.
Access other apps' media files
To access media files that other apps have created, you must declare the appropriate storage-related permissions, and the files must reside in one of the following media collections
To access only media files you should checkout:
Access media files from shared storage
Request All files access
An app can request All files access from the user by doing the following: Declare the MANAGE_EXTERNAL_STORAGE permission in the manifest.
Use the ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent action to direct users to a system settings page where they can enable the following option for your app: Allow access to manage all files.
To determine whether your app has been granted the MANAGE_EXTERNAL_STORAGE permission, call Environment.isExternalStorageManager().
If your app is a file manager type app then only you can get the permission to manage all the files. Read more here Manage all files on a storage device

Internal or External storage for editable app-specific file

I am creating an app that requier an app-specific file that I called "conf.cfg" for example. this file need to be read by my application to create some object etc... the body of the file look like that :
#activation, level, type, regex or array
0, "critic", 0,"\\d{4}\\w\\d{3}"
1, "critic", 1, [word1,word2]
1,"minor", 0,"\\d{2}-\\w{3}-\\d{4}\\s?\\/?\\s?\\d{2}:\\d{2}"
Doing my research I found that there is two type of Storage in android :
Internal storage :
Internal storage is best when you want to be sure that neither the user nor other apps can access your files.
External storae :
External storage is the best place for files that don't require access restrictions and for files that you want to share with other apps or allow the user to access with a computer.
As I want the user to be able to edit/download/upload/USE this file, External Storage seems to be a good choice. However on Developper Android they said :
Caution: The external storage might become unavailable if the user removes the SD card or connects the device to a computer. And the files are still visible to the user and other apps that have the READ_EXTERNAL_STORAGE permission. So if your app's functionality depends on these files or you need to completely restrict access, you should instead write your files to the internal storage.
Caution: Files on external storage are not always accessible, because users can mount the external storage to a computer for use as a storage device. So if you need to store files that are critical to your app's functionality, you should instead store them on internal storage.
As this file need to be always available and is critical to my app's functionality
So... Internal Storage seems to be better. But I need the user to see and be able to use the file. And here I'm stuck.
Anyone has an idea of where and how to put/create this file ?
EDIT : following #greenapps answer
heer is a piece of code I've wrote. I use the getExternalFilesDir(null) command to write and store my file
String folderName = "Innovation";
String confFileName = "conf.txt";
String commentSymbol = "#";
String commentLine = commentSymbol + " activation, level, type , regex or array";
File storage = getExternalFilesDir(null);
File folder = new File(storage, folderName);
File conf = new File(folder, confFileName);
Log.d(TAG, "Folder action!");
if (!folder.exists()) {
if (folder.mkdirs()) {
Log.d(TAG, "Created : " + folder.getAbsolutePath());
} else {
Log.e(TAG, "folder not created!");
}
}
Log.d(TAG, "File action!");
if (!conf.exists()) {
try {
Log.d(TAG, "opening...");
FileOutputStream fos = new FileOutputStream(conf);
fos.write(commentLine.getBytes());
fos.close();
Log.d(TAG, "Created : " + conf.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
if (conf.exists()) {
Log.d(TAG, "File exist at : " + conf.getAbsolutePath());
}
the file is created, as shown by the last log
Created : /storage/emulated/0/Android/data/com.aralex.innovation/files/Innovation/conf.txt
But when I search the file with the native file explorer application of the phone, I can't find it. I can go to the file folder but the folder "Innovation/" is hidden.
This is a problem because I want the file to be visible.
Phone : Samsung s7, s7edge, s9+
Default File Explorer Icon
Default File Explorer Oppened
Well I finally found an answer myself.
On this post Android create folders in Internal Memory #prodev specify that Environment.getExternalStorageDirectory() is a good place, because the file will be accessible and :
note that ExternalStorage in Environment.getExternalStorageDirectory() does not necessarily refers to sdcard, it returns phone primary storage memory
it requires permissions (only for build version >= M) :
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
So here is a code to answer my problem (it ask permission on runtime) :
private ArrayList<Rule> ruleList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[...]
// Check for the storage permission before accessing the camera. If the
// permission is not granted yet, request permission.
if (hasPermissions(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
ruleList = createRules();
} else {
requestStoragePermission();
}
}
private boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
Log.d(TAG, "Checking permission : " + permission);
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "not granted : " + permission);
return false;
} else {
Log.d(TAG, "granted : " + permission);
}
}
}
return true;
}
/**
* Handles the requesting of the storage permission. This includes
* showing a "Snackbar" errorMessage of why the permission is needed then
* sending the request.
*/
private void requestStoragePermission() {
Log.w(TAG, "Storage permission is not granted. Requesting permission");
final String[] permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_EXTERNAL_PERM);
return;
}
final Activity thisActivity = this;
View.OnClickListener listener = view -> ActivityCompat.requestPermissions(thisActivity, permissions,
RC_HANDLE_EXTERNAL_PERM);
Snackbar.make(findViewById(android.R.id.content), R.string.permission_storage_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, listener)
.show();
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode != RC_HANDLE_EXTERNAL_PERM) {
Log.d(TAG, "Got unexpected permission result: " + requestCode);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
return;
}
if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Storage permission granted");
// We have permission
ruleList = createRules();
return;
}
Log.e(TAG, "Permission not granted: results len = " + grantResults.length +
" Result code = " + (grantResults.length > 1 ? grantResults[0] + " " + grantResults[1] : grantResults.length > 0 ? grantResults[0] : "(empty)"));
DialogInterface.OnClickListener listener = (dialog, id) -> finish();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Assisting Tool")
.setMessage(R.string.no_storage_permission)
.setPositiveButton(R.string.ok, listener)
.show();
}
private ArrayList<Rule> createRules() {
Log.d(TAG, "=========================READING FILE======================");
ArrayList<Rule> ruleList = new ArrayList<>();
String folderName = "Innovation";
String confFileName = "conf.txt";
String commentSymbol = "#";
String commentLine = commentSymbol + " activation, level, type , regex or array";
File storage = Environment.getExternalStorageDirectory();
File folder = new File(storage, folderName);
File conf = new File(folder, confFileName);
Log.d(TAG, "Folder action!");
if (!folder.exists()) {
if (folder.mkdirs()) {
Log.d(TAG, "Created : " + folder.getAbsolutePath());
} else {
Log.e(TAG, "folder not created!");
}
}
Log.d(TAG, "File action!");
if (!conf.exists()) {
try {
Log.d(TAG, "opening...");
FileOutputStream fos = new FileOutputStream(conf);
fos.write(commentLine.getBytes());
fos.close();
Log.d(TAG, "Created : " + conf.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
if (conf.exists()) {
Log.d(TAG, "File exist at : " + conf.getAbsolutePath());
} else {
Log.e(TAG, "The file doesn't exist...");
}
}
Now it create a app-specific file
/storage/emulated/0/Innovation/conf.txt
that is accessible by user !
So external storage.
No internal as file explorers have no access to your apps private internal memory.
You could use getExternalFilesDir(null) as then you dont need read and write permissions

Android 6.0 Write to external SD Card

I tried everything to write on external SD card on Android 6.0, but I am not able to write on it.
I did research on stackoverflow and found lot of things but none works. Here is my code
String extPath = System.getenv("SECONDARY_STORAGE") + "/Android/data/com.gvm.externalstorage.externalstoragetest/";
File file = new File(extPath,"myFiles");
if (!file.exists()) {
boolean dirResult = file.mkdirs();
Log.e("Directory Exist", dirResult + " Directory created");
} else {
Log.e("Directory Exist", "Exist");
Log.e("Direcotry Path",file.getAbsolutePath());
}
//String displayname = fileName.replace("%20", " ");
File outputFile = new File(file, "mytest5.txt");
outputFile.createNewFile();
This code works on Android 5.0 but not on Android 6.0.
Then I tried this path as well, and that gives me permission error, I have set all permission and managed code for runtime permission as well.
/mnt/media_rw/6AC9-083B
File write failed: java.io.IOException: open failed: EACCES (Permission denied)
If anyone can help me it would be great as I am trying this since last 3 days.
Thanks,
Anvesh
After long hard work I figured out a solution. In Android 6.0 it's not going to give you SD Card path always using this:
System.getenv("SECONDARY_STORAGE")
or this
Environment.getExternalStorageDirectory()
So I retrieved external SD Card path using this
File[] fs = context.getExternalFilesDirs(null);
String extPath = "";
// at index 0 you have the internal storage and at index 1 the real external...
if (fs != null && fs.length >= 2)
{
extPath = fs[1].getAbsolutePath();
Log.e("SD Path",fs[1].getAbsolutePath());
}
Rest everything will remain same for permission and all.
Thanks to those who helped me.
From API 23+(6.0) you need to request the read/write permissions even if they are already in your manifest known as Requesting Permissions at Run Time.
from docs
Beginning in Android 6.0 (API level 23), users grant permissions to
apps while the app is running, not when they install the app. This
approach streamlines the app install process, since the user does not
need to grant permissions when they install or update the app. It also
gives the user more control over the app's functionality; for example,
a user could choose to give a camera app access to the camera but not
to the device location. The user can revoke the permissions at any
time, by going to the app's Settings screen.
java
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* #param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I think u should check your app permission first, to make sure your storage permission has been turned on.
If there's no storage permission:
Please check if u use this permission in your AndroidManifest
<uses-permission android:name="android.permission.STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
If the storage permission has been turned off:
Please check your runtime permission, maybe u can refer to this code
private void checkPermissions() {
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return;
}
final List<String> permissionsList = new ArrayList<String>();
permissionsList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
permissionsList.add(Manifest.permission.WRITE_CALENDAR);
permissionsList.add(Manifest.permission.READ_PHONE_STATE);
int permissionCheckLocation = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
int permissionCheckStorage = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permissionCheckCalendar = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.WRITE_CALENDAR);
int permissionCheckPhoneState = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.READ_PHONE_STATE);
boolean locationPermission=permissionCheckLocation == PackageManager.PERMISSION_GRANTED?true:false;
boolean storagePermission=permissionCheckStorage == PackageManager.PERMISSION_GRANTED?true:false;
boolean calendarPermission=permissionCheckCalendar == PackageManager.PERMISSION_GRANTED?true:false;
boolean phoneStatePermission=permissionCheckPhoneState == PackageManager.PERMISSION_GRANTED?true:false;
boolean shouldShowLocationPermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
boolean shouldShowStoragePermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
boolean shouldShowCalendarPermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.WRITE_CALENDAR);
boolean shouldShowPhoneStatePermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.READ_PHONE_STATE);
if (permissionCheckLocation == PackageManager.PERMISSION_GRANTED && permissionCheckStorage == PackageManager.PERMISSION_GRANTED
&& permissionCheckCalendar == PackageManager.PERMISSION_GRANTED && permissionCheckPhoneState == PackageManager.PERMISSION_GRANTED){
return;
}else if(((!locationPermission&&!shouldShowLocationPermission)||(!storagePermission&&!shouldShowStoragePermission)
||(!calendarPermission&&!shouldShowCalendarPermission)||(!phoneStatePermission&&!shouldShowPhoneStatePermission))&&appContext.localCheckPermission){
showMessageOKCancel("You need to allow access these permissions",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 1);
}
});
}else{
ActivityCompat.requestPermissions(IntroductionActivity.this, permissionsList.toArray(new String[permissionsList.size()]), 0);
}
}
If still have problem, please try to change your file path :
String fileName="mytest5.txt";
File folder = new File(Environment.getExternalStorageDirectory().getPath() + "/com.gvm.externalstorage.externalstoragetest/");
if (!folder.exists()) {
try {
folder.mkdirs();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Default Save Path Creation Error:" + folder);
}
}
File logFile = new File(folder, fileName);
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Default Save Path Creation Error:" + logFile);
}
}
Best regards. I hope this can help u
#Anvesh Another reliable method i'm using:
/**
* Get external storage path use reflect on android 6.0 device.
* Source code:
* https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/storage/StorageVolume.java
*
* #param removable the sdcard can remove or not, true means external sdcard, false means
* internal sdcard.
* #return path of sdcard we want
*/
public static String getStoragePath(boolean removable) {
WinZipApplication application = WinZipApplication.getInstance();
Context mContext = application.getApplicationContext();
StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClazz = null;
try {
storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
Method getPath = storageVolumeClazz.getMethod("getPath");
Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
Object result = getVolumeList.invoke(mStorageManager);
final int length = Array.getLength(result);
for (int i = 0; i < length; i++) {
Object storageVolumeElement = Array.get(result, i);
String path = (String) getPath.invoke(storageVolumeElement);
boolean mRemovable = (Boolean) isRemovable.invoke(storageVolumeElement);
if (removable == mRemovable) {
return path;
}
}
} catch (Exception e) {
return null;
}
return null;
}
After a lot of research I found ABSOLUTE SOLUTION. IT WORKS.
public boolean checkStorage() {
File[] fs = con.getExternalFilesDirs(null);
if (fs.length == 2)
return true;
else
return false;
}

Not able to create the folder in external storage in marshmallow version

when I try to run this code in marshmallow the folder was not created..
the code is,I tried to run the same code its working fine except marshmallow
File folder = new File(Environment.getExternalStorageDirectory() + "/abcdefg");
boolean success = false;
if (!folder.exists()) {
success = folder.mkdir();
}
if (!success) {
Log.d("", "Folder not created.");
} else {
Log.d("", "Folder created!");
}
Try to add below code in your activity for requesting runtime permission.
Your need to require READ_EXTERNAL_STORAGE permission to create folder(directory) in external storage.
if (ActivityCompat.checkSelfPermission(YourActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_FOR_STORAGE);//REQUEST_FOR_STORAGE=1111
} else {
//Do your stuff here
}
...
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(requestCode == REQUEST_FOR_STORAGE){
//Do your stuff here
}
}
Hope its help you.
As marshmallow introduce Run time Permission you have to check for the permission
in run time. You can refer here
1.https://developer.android.com/training/permissions/requesting.html
2.https://www.youtube.com/watch?v=iZqDdvhTZj0
3.https://www.youtube.com/watch?v=C8lUdPVSzDk
You have to accept the STORAGE permission group from the user dynamically.
Go with the below link
http://developer.android.com/guide/topics/security/permissions.html

Android M Run time Permission issue

I have search a lot about this problem but i didn't find any solution why this happening?
Currently i have face strange problem with run time permission ,i'm trying to ask runtime permission for camera and it's work fine but my problem is when user allow the permission my code for pick video from gallery and make thumbnail with ThumbnailUtils but it will return null once when my app is install first time i mean when user first time allow for permission it will return null after all the cases thumbnailutil works fine,As well as below android M its work fine for first time too.
What I'm currently doing is
Ask for appropriate permission and after check allow or deny further i process for select video from gallery as per my requirement
-----------------Camera Permission-----------------
public void requestPermissionForCamera() {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)) {
Toast.makeText(activity, "Camera permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
}
}
-----------------External Storage permission--------------------
public void requestPermissionForExternalStorage() {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(activity, "External Storage permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
}
}
Below is my onRequestPermissionsResult & onActivityResult
UPDATE:
#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) {
// my code for open video or image gallery
} else {
//SnackBar "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission"
}
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == FragmentActivity.RESULT_OK) {
if (requestCode == SELECT_VIDEO) {
Uri videoUri = data.getData();
selectedVideoPath = getRealPathFromURI(videoUri);
if (selectedVideoPath == null) {
Log.e("vediotag", "selected video path = null" + selectedVideoPath);
} else {
Log.e("vediotag", "selected video path----" + selectedVideoPath);
//create video thumbnail
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(selectedVideoPath, MediaStore.Video.Thumbnails.MINI_KIND);
insertData(mimageTitle, bitmap, selectedVideoPath);
}
}
}
}
public String getRealPathFromURI(final Uri contentURI) {
Cursor cursor = getActivity().getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
return contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
if (idx == -1) {
return contentURI.getPath();
}
String rvalue = cursor.getString(idx);
cursor.close();
return rvalue;
}
}
Problem Which i'm currently facing
Above my code is working fine after activity recreate once,but it fail for the first time when i have install app and allow for permission.
NOTE:
I don't want to recreate activity programmatically so don't suggest me for doing that.
Any help will be much appreciated
Regards.

Categories

Resources