I'm creating an social media platform where photos that are already on the device can be uploaded to the platform. I found a sample on github that (in theory) should enable me to read all the jpg/png files and show them in a recyclerview. The code to obtain the files is shown below.
private void createImageGallery() {
File storageDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
mGalleryFolder = new File(storageDirectory, GALLERY_LOCATION);
Log.i("gallery", "" + (mGalleryFolder != null));
Log.i("gallery", mGalleryFolder.toString());
if (!mGalleryFolder.exists()) {
boolean mk = mGalleryFolder.mkdirs();
Log.i("gallery", "mkdirs returns " + mk);
}
}
The first log statement equates to true, the second shows the string
"/storage/emulated/0/Pictures/hilarity_image"
the third log statement says the boolean mk is false. The File object mGalleryFolder is then passed into the constructor for a recyclerview adapter. The error is thrown when adapter.getItemCount() is called. Code is shown below
public int getItemCount() {
return mGalleryFolder.listFiles().length;
}
The some of the permissions from the manifest are shown below
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Apparently, .length() is being called on a null object. I assumed this had something to do with mkdirs() returning false. Is this assumption correct? How do I make it so mkdirs() returns true? Remember, the desired result is showing all the photos that are already on the device in a recyclerview, if my approach to this problem is incorrect, please correct me.
The directory is not created. So you should not continue with your code but stop.
Now you try to list the files in a directory that does not exist. No wonder that listFiles returns null then.
For Android 6+ you need to add code to ask the user to confirm the permissions you request in manifest.
Google for runtime permissions.
After adding the code you can create that directory.
Related
I have been trying various ways to call on my location data ranging from IP location API's to Flutter plugin's but have not been able to get accurate location data for any of them. Through all I have settled onto Geolocator. But I kept getting
I/flutter ( 5206): null
I/flutter ( 5206): GeolocationStatus.unknown
When calling it in my Init state as follows:
void initState() {
super.initState();
fetchData();
}
fetchData() async {
setState(() {
isLoading = true; //Data is loading
});
GeolocationStatus geolocationStatus =
await Geolocator().checkGeolocationPermissionStatus();
position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
if (position != null) {
lastPosition = await Geolocator()
.getLastKnownPosition(desiredAccuracy: LocationAccuracy.high);
}
...
if (position != null)
print(position);
else
print(lastPosition);
print(geolocationStatus);
setState(() {
isLoading = false; //Data has loaded
});
}
After some research I decided to settle on permission_handler to try to check permissions. I declared PermissionStatus _status added the following lines to my fetchData() function:
PermissionHandler()
.checkPermissionStatus(PermissionGroup.location);
To which I get No permissions found in manifest for: 3
My manifest has the permissions to the best of my understanding. Manifest file: https://gist.github.com/Purukitto/640d1637c05bdb1b69cc4309947c45d5
From what I understand adding the permissions to the Manifest should add the permission option at least to the app, but after building and installing the app there are "No permissions" for my app(Screenshot attached).
What could be the problem. I have tried to mention all relevant things. Any insight will be really helpful.
This question is linked in the Flutter package permission_handler's ReadMe as an example of setting up the AndroidManifest.xml for asking permissions.
If you're having issues with the device asking the user for permissions, this may be your culprit.
To elaborate on rollcake's answer:
1. If you don't know what permissions you need yet, go to the Android Developer page to see the list and the syntax(es).
2. In your project, open: android/app/src/main/AndroidManifest.xml
3. Insert your permissions as shown in this example here:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.your.package">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name="io.flutter.app.FlutterApplication"
...<and so on>...
Just a side note: There are different AndroidManifest.xml files in your project (...src/debug, ...src/profile, and ...src/main). Adding the permissions to the main version described above should work but if you're noticing inconsistent behavior make sure you're putting all of your permissions in the same AndroidManifest file.
Check for targetSdkVersion is 23 if so then check for runtime permission you can use checkSelfPermission() and requestPermissions() for android 6 and above
open android project in flutterProject
click manifests file
insert permission
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
1. Add them in AndroidMenifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="30"></uses-permission>
<uses-permission android:name="com.google.android.gms.permission.AD_ID"></uses-permission>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"></uses-permission>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"></uses-permission>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"></uses-permission>
2. Update permissions handler package :
Package link : https://pub.dev/packages/permission_handler
I'm developing a little sdk that has to be included in projects via .aar file. In this sdk I have a method defined like below:
/**
* Sends an "open lock" request for the bike, with the ble name provided as param. Requires ACCESS_FINE_LOCATION and
* BLUETOOTH permission
*
* #param bikeBleName The BLE name of the searched bike, normally starts with 'BS' prefix
* #param listener Listener for the operation state, returns success or an error string with the detailed error
*/
#RequiresPermission(allOf = [Manifest.permission.BLUETOOTH, Manifest.permission.ACCESS_FINE_LOCATION])
override fun startRent(bikeBleName: String, bikeMode: BikeMode, listener: StartRentListener) {
GlobalScope.launch {
startRentManager.startRent(bikeBleName, bikeMode, listener)
}
}
As you can see, the method is annotated with #RequiresPermission(allOf = [Manifest.permission.BLUETOOTH, Manifest.permission.ACCESS_FINE_LOCATION]), however, if I call the method from my project MainActivity, Android Studio tells me that the method requires a permission check, but it doesn't tell me which permissions are required.
What I would like to obtain is Android Studio telling me "this method requires ACCESS_FINE_LOCATION and BLUETOOTH permissions", something similar to the screenshot below. How can I achieve that? Thanks
The manifest file of the library module is:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.zehus.bikeaccesssdk">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
</manifest>
Problem was that I placed
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.zehus.bikeaccesssdk">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
</manifest>
in the library module. I removed the permissions from the library manifest and now Android Studio is providing the correct hint.
I've read a really lot of posts yet, but the problem still occurs...
My app needs calendar permission, and this wil work fine till Android 5.
In my trap.xml in the permissions ar set as followed:
<android xmlns:android="http://schemas.android.com/apk/res/android">
<manifest>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
</manifest>
</android>
When I try to set the permission like I found on Jira:
function calenderTask() {
if (Ti.Calendar.hasCalendarPermissions()) {
showCalendars(Ti.Calendar.selectableCalendars);
} else {
Ti.Calendar.requestCalendarPermissions(function(e) {
if (e.success) {
showCalendars(Ti.Calendar.selectableCalendars);
} else {
Ti.API.error(e.error);
alert('Access to calendar is not allowed');
}
});
}
}
function showCalendars(calendars) {
for (var i = 0; i < calendars.length; i++) {
Ti.API.info("Calender: "+calendars[i].name);
}
}
calenderTask();
only after a fresh install on the device (Samgung S7, Android 6) there is some action when I place an alert in the code.
The next run it looks like the code is ignored.
And... most important of all, there is no permissions set.
When I manually set the permission in the settings of my device, the app works fine.
Please is there somebody with a solution for me?
I'm also trying to find a better way of checking Calendar permissions on Android 6.
Meanwhile, I'm using this code to send the user right to the app settings on a dialog:
var dialog = Ti.UI.createAlertDialog();
dialog.message = 'Please check your calendar permissions';
dialog.cancel = 1;
dialog.buttonNames = ['Settings', 'Cancel'];
dialog.addEventListener('click', function(e){
var intentData = {action: "android.settings.APPLICATION_DETAILS_SETTINGS", data: "package:" + Ti.App.getId()};
var flags = [ Ti.Android.FLAG_ACTIVITY_NEW_TASK, Ti.Android.FLAG_ACTIVITY_NO_HISTORY, Ti.Android.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS];
if (e.index === 0){
win.openIntent(intentData, flags);
}
});
dialog.show();
I hope it helps a bit...
I found a solution/workaround for my problem that the calendar permission was not asked for.
In the settings section of the device I removed the permissions by hand by the specific app. Now I did a reset on all settings of the installed app's and then the question is asked on the device when I start the particular part of the app.
Thus just remove the permissions and delete the app from the device is not enough!
I've used the part of code that I listed before, that from Jira.
So, for the moment my problem is solved (I think) and the app is asking for the needed permissions after first install.
Carlos, thanks for your comment, and I hope you can do something with my investigations too.
I'm trying to write a continuous stream of data to android wear locally on the wear device. I've a class called DataSaver that works perfectly fine on the phone side, but the same code would not work on the wear device. I've android permission for write, and read on both wear and mobile.
In the constructor for DataSaver, I've the following:
if (!isExternalStorageWritable()) Log.e(TAG, "External storage is not writable"); //This line does not show anything on the log. So, esExternalStorageWritable returns false.
File rootDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);//Environment.getExternalStorageDirectory();
if (!rootDir.canWrite())
{
Log.d(TAG, "cannot write in the root: "+rootDir.toString()+", space: "+rootDir.getUsableSpace()+", can read: "+rootDir.canRead()+", list: "+rootDir.list());
}
Function isExternalStorageWritable() is implemented as follows:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable()
{
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state))
{
return true;
}
return false;
}
This always goes inside the if statement where I'm checking if rootDir can write. The rootDir.canRead also returns false. The free space on the device is returned as 2.2GB.
The mkdirs in later lines after that fails because it cannot write to root. Any ideas, suggestions? I would greatly appreciate it.
The problem was I had to manually give permission in settings on the watch for it to work. Basically go to: Settings -> Permissions -> Your app, and check if storage is disabled (it was in my case). Click once to toggle the value.
Remember to have write permission on manifest.
Normal way to do that is checking whether the manifest uses WRITE_EXTERNAL_STORAGE permission:
String permission = "android.permission.WRITE_EXTERNAL_STORAGE";
int res = context.checkCallingOrSelfPermission(permission);
return (res == PackageManager.PERMISSION_GRANTED);
My question is in about using canWrite() method.Docs say:
public boolean canWrite ()
Added in API level 1
Indicates whether the
current context is allowed to write to this file.
So we can use this method to check permission like this:
Environment.getExternalStorageDirectory().canWrite();
This way seems to be simpler than first way and also does not need to use Context.Also we can use same to check read permission.But is this a good way to check those?Also is it a good way to check if manifest uses read/write permissions?