I am developing an SDK(.aar) which third parties can consume. In my sample application when I use the aar, I can see that the application doesnt prompt for the camera permission. When I open the aar and see its manifest.xm, it contains the below:
<!-- WRITE_EXTERNAL_STORAGE is needed because we are storing there the config files of KM -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.read_external_storage" />
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.sensor.accelerometer" />
Since the camera is present as a required permission can anyone tell me why it is not coming up when installing the sample app.
Since Android 6.0 you have to request the permssions at runtime and the user is not prompted at the time of installation.
https://developer.android.com/training/permissions/requesting.html
Here is how i check for permissions:
public boolean permissionsGranted() {
boolean allPermissionsGranted = true;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
boolean hasWriteExternalPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
boolean hasReadExternalPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
boolean hasCameraPermission = (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED);
if (!hasWriteExternalPermission || !hasReadExternalPermission || !hasCameraPermission) {
allPermissionsGranted = false;
}
}
return allPermissionsGranted;
}
This is how i make the request if permissionsGranted() method returns false
String[] permissions = {android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA, android.Manifest.permission.READ_EXTERNAL_STORAGE};
ActivityCompat.requestPermissions(this, permissions, 1);
And you have to override onRequestPermissionsResult method, below is what i have in mine.
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1: {
boolean startActivity = true;
for (int i = 0; i < grantResults.length; i++) {
if (grantResults.length > 0 && grantResults[i] != PackageManager.PERMISSION_GRANTED) {
String permission = permissions[i];
boolean showRationale = shouldShowRequestPermissionRationale(permission);
if (!showRationale) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null);
intent.setData(uri);
startActivityWithIntent(intent);
Toast.makeText(this, "Enable required permissions", Toast.LENGTH_LONG).show();
startActivity = false;
break;
} else {
Toast.makeText(this, "Enable required permissions", Toast.LENGTH_LONG).show();
break;
}
}
}
if(startActivity) {
getActivity().finish();
startActivityWithIntent(getIntent());
}
}
}
}
public void startActivityWithIntent(Intent intent){
startActivity(intent);
}
showRationale is to check if user ticked never ask again, if so then i start the settings activity so that user can enable permissions.
Let me know if you need more clarity
Related
I am relatively new to Android development. I have an app which requires the certain permissions. These are added in the AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.STORAGE"/>
<uses-permission android:name="android.permission.PHONE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
The app crashes on initial start (both on emulated device and installed apk) but after granting the CAMERA, PHONE and STORAGE permissions manually from the settings of phone, it works fine.
In the MainActivity, I have also added permission check like these (in onCreate):
// CAMERA permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
1);
}
But the app keeps crashing on start without showing the permission dialog. What am I doing wrong here?
EDIT
Error trace:
You can try below code, this works for me. Its for camera and storage. Call this method checkAndRequestPermissions();
private void checkAndRequestPermissions() {
int PERMISSION_ALL = 1;
String[] PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
if (!hasPermissions(this, PERMISSIONS)) {
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}
}
public static boolean hasPermissions(Context context, String... permissions) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//granted
} else {
//not granted
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
showDialogOK(getString(R.string.app_permission_allow),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
}
}
});
}
//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
showDialogOK(getString(R.string.app_permission_necessary),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
finish();
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
break;
}
}
});
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
I'm trying to request the ability to read contacts in an app, and have followed several tutorials. All of these use nearly the same code for this process. Below is the code in my MainActivity.java file, that should request permission.
private void checkContactPermissions()
{
if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "Contacts permission NOT granted");
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
}
else
{
Log.i(TAG, "Contacts permission granted");
readContacts();
}
}
My manifest.xml also includes the line:
<uses-permission android:name="android.permission.READ_CONTACTS" />
When the app is run, either on emulator or physical debugging device, it does not ask for permission, however the log states that the permission was granted. I have confirmed the permission is off by going to the settings and checking it was turned off. What else would be causing the app to perform as if permissions were granted.
Try this,
private Context mContext=YourActivity.this;
private static final int REQUEST = 112;
if (Build.VERSION.SDK_INT >= 23) {
String[] PERMISSIONS = {android.Manifest.permission.READ_CONTACTS};
if (!hasPermissions(mContext, PERMISSIONS)) {
ActivityCompat.requestPermissions((Activity) mContext, PERMISSIONS, REQUEST );
} else {
readContacts();
}
} else {
readContacts();
}
get Permissions Result
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts();
} else {
Toast.makeText(mContext, "The app was not allowed to read your contact", Toast.LENGTH_LONG).show();
}
}
}
}
check permissions for marshmallow
private static boolean hasPermissions(Context context, String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
Manifest
<uses-permission android:name="android.permission.READ_CONTACTS" />
I use RxPermission for permissions to make my code ultimately short.
First add these permissions (or one you need) in your manifest.xml.
<uses-permission android:name="android.permission.READ_CONTACTS" />
Then ask run time permission from user in your activity.
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.READ_CONTACTS) // ask single or multiple permission once
.subscribe(granted -> {
if (granted) {
// All requested permissions are granted
} else {
// At least one permission is denied
}
});
add this library in your build.gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
}
Isn't this easy?
As Divyesh Patel pointed out, I had the boolean statemetns mixed up, it should be
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED)
Rather than
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED)
Important thing for you to note here that these permissions are asked only for devices with version>23 and if you have lower version of android then for only some models like redmi you have to invoke the permissions manually .
Otherwise version<23 generally do not ask for permissions.
If you put in manifest. It will automatically take it, specially when you are installing app over usb.
If any device has OS version below <23 or In app manifist file maxtarget version is below <23 then it will not ask permission in runtime because while the app installing on these devices you actually giving permission to all you mentioned.
So the runtime permissions are possible only in the case of device has OS version above 22(Lolipop).
Hope this helpful..
#Rajesh
I want to get permissions for ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION in android but for whatever reason it only grants permission for ACCESS_COARSE_LOCATION .
My activity:
final int PERMISSION_ALL = 1;
String[] PERMISSIONS = {ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION};
if(!hasPermissions(this, PERMISSIONS)){
System.out.println("=========================================nottttt========================================================");
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}
#Override
public void onRequestPermissionsResult(int requestCode, String PERMISSIONS[], int[] grantResults) {
System.out.println("==================requesttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt");
switch (requestCode) {
case PERMISSION_ALL: {
System.out.println("lengthhhhhhhhhhhhhhhhhhhhhh"+PERMISSIONS.length);
for (int i = 0; i < PERMISSIONS.length; i++) {
String permission = PERMISSIONS[i];
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
System.out.println(permission + "is alreadyyyyyyyyyyyyy grantedddddddddddddddd");
} else {
System.out.println(permission + "is not grantedddddddddddddddd");
}
return;
}
}
}
}
public static boolean hasPermissions(Context context, String[] permissions) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
Android manifest:
<user-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<user-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
I start the app, I am prompted to give access to the location, I choose yes , but ACCESS_FINE_LOCATION is not granted.Can somebody help me find the problem?
Once the user granted permission to one of those permissions, the permission for the other will be granted too. You can't have one of them granted and the other not granted.
ACCESS_FINE_LOCATION permission allow app to use GPS and Network location providers. But, Network provider is a coarse location provider. That is why, if you request ACCESS_FINE_LOCATION first, it will request ACCESS_COARSE_LOCATION permission authomatically
I have this app that will pick image to gallery and display it to the test using Imageview. My problem is it won't work on Android M. I can pick image but won't show on my test.They say i need to ask permission to access images on android M but don't know how. please help.
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app.
Type 1- When your app requests permissions, the system presents a dialog box to the user. When the user responds, the system invokes your app's onRequestPermissionsResult() method, passing it the user response. Your app has to override that method to find out whether the permission was granted. The callback is passed the same request code you passed to requestPermissions().
private static final int PICK_FROM_GALLERY = 1;
ChoosePhoto.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick (View v){
try {
if (ActivityCompat.checkSelfPermission(EditProfileActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(EditProfileActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PICK_FROM_GALLERY);
} else {
Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, PICK_FROM_GALLERY);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults)
{
switch (requestCode) {
case PICK_FROM_GALLERY:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, PICK_FROM_GALLERY);
} else {
//do something like displaying a message that he didn`t allow the app to access gallery and you wont be able to let him select from gallery
}
break;
}
}
Type 2- If you want to give runtime permission back to back in one place then you can follow below link
Android 6.0 multiple permissions
And in Manifest add permission for your requirements
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Note- If Manifest.permission.READ_EXTERNAL_STORAGE produce error then please replace this with android.Manifest.permission.READ_EXTERNAL_STORAGE.
==> If you want to know more about runtime permission then please follow below link
https://developer.android.com/training/permissions/requesting.html
-----------------------------UPDATE 1--------------------------------
Runtime Permission Using EasyPermissions
EasyPermissions is a wrapper library to simplify basic system permissions logic when targeting Android M or higher.
Installation
Add dependency in App level gradle
dependencies {
// For developers using AndroidX in their applications
implementation 'pub.devrel:easypermissions:3.0.0'
// For developers using the Android Support Library
implementation 'pub.devrel:easypermissions:2.0.1'
}
Your Activity (or Fragment) override the onRequestPermissionsResult method:
#Override
public void onRequestPermissionsResult(int requestCode, String[]
permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions,grantResults);
// Forward results to EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
Request Permissions
private static final int LOCATION_REQUEST = 222;
Call this method
#AfterPermissionGranted(LOCATION_REQUEST)
private void checkLocationRequest() {
String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION};
if (EasyPermissions.hasPermissions(this, perms)) {
// Already have permission, do the thing
// ...
} else {
// Do not have permissions, request them now
EasyPermissions.requestPermissions(this,"Please grant permission",
LOCATION_REQUEST, perms);
}
}
Optionally, for a finer control, you can have your Activity / Fragment implement the PermissionCallbacks interface.
implements EasyPermissions.PermissionCallbacks
#Override
public void onPermissionsGranted(int requestCode, List<String> list) {
// Some permissions have been granted
// ...
}
#Override
public void onPermissionsDenied(int requestCode, List<String> list) {
// Some permissions have been denied
// ...
}
Link -> https://github.com/googlesamples/easypermissions
-----------------------------UPDATE 2 For KOTLIN--------------------------------
Runtime Permission Using florent37
Installation Add dependency in App level gradle
dependency
implementation 'com.github.florent37:runtime-permission-kotlin:1.1.2'
In Code
askPermission(
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) {
// camera or gallery or TODO
}.onDeclined { e ->
if (e.hasDenied()) {
AlertDialog.Builder(this)
.setMessage(getString(R.string.grant_permission))
.setPositiveButton(getString(R.string.yes)) { dialog, which ->
e.askAgain()
} //ask again
.setNegativeButton(getString(R.string.no)) { dialog, which ->
dialog.dismiss()
}
.show()
}
if (e.hasForeverDenied()) {
e.goToSettings()
}
}
Link-> https://github.com/florent37/RuntimePermission
public void pickFile() {
int permissionCheck = ContextCompat.checkSelfPermission(getActivity(),
CAMERA);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
getActivity(),
new String[]{CAMERA},
PERMISSION_CODE
);
return;
}
openCamera();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[],
#NonNull int[] grantResults) {
if (requestCode == PERMISSION_CODE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openCamera();
}
}
}
private void openCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_CODE);
}
<uses-permission android:name="android.permission.CAMERA" />
Trying to make a painting app. Everything but the save button is functioning as intended. Whenever I click the save button, it's not saving and I'm getting an error java.lang.SecurityException: Permission Denial: writing com.android.providers.media.MediaProvider uri content://media/external/images/media from pid=10397, uid=10298 requires android.permission.WRITE_EXTERNAL_STORAGE, or grantUriPermission().
else if(view.getId()==R.id.save_btn){
//save drawing
AlertDialog.Builder saveDialog = new AlertDialog.Builder(this);
saveDialog.setTitle("Save drawing");
saveDialog.setMessage("Save drawing to device Gallery?");
saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
//save drawing
}
});
saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
saveDialog.show();
drawView.setDrawingCacheEnabled(true);
String imgSaved = MediaStore.Images.Media.insertImage(
getContentResolver(), drawView.getDrawingCache(),
UUID.randomUUID().toString()+".png", "drawing");
In the manifest I have
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
you can just wrap your code like this:
//check permission is granted or no
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RESULT);
}
else
{
//your code
}
You have to write storage permission on Manifest fie.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Also for Marshmallow you have to write code for checking and granting storage permission.
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
return true;
}
If you need to ask permission then below code works.
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
Result callback for permission will be.
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
//resume tasks needing this permission
}
}