Related
I want to request BLUETOOTH_SCAN and BLUETOOTH_CONNECT permission. Could anyone tell me how should I do that in Kotlin? I have this piece of code but it always tells permission denied.
class MainActivity : AppCompatActivity() {
var requestBluetooth = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
Toast.makeText(this, "granted", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(this, "denied", Toast.LENGTH_SHORT).show()
}
}
private val requestMultiplePermissions =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
permissions.entries.forEach {
Log.d("test", "${it.key} = ${it.value}")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button) // just a simple button from XML file
button.setOnClickListener {
// for android 12
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
requestMultiplePermissions.launch(arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT))
}
else{
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
requestBluetooth.launch(enableBtIntent)
}
}
}
}
Because I am not yet well-versed in Kotlin (and I expect you to be able to easily convert the Java codes into Kotlin), I'll just show you how to request the dangerous Manifest.permission.BLUETOOTH_CONNECT permission every time we want to access the list of paired Bluetooth devices:
public static final int PERMISSIONS_REQUEST_BLUETOOTH_CONNECT = 101; //the int value must be unique
public boolean checkBluetoothConnectPermission(Activity activity) {
boolean permitted = false;
Boolean bluetoothAlreadyGranted = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ?
ActivityCompat.checkSelfPermission(activity,
Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED: true;
Log.i(IMapView.LOGTAG,
String.format("PERMISSION: checkBluetoothPermission(%s) bluetoothAlreadyGranted=%s",
activity.getClass().getSimpleName(),
bluetoothAlreadyGranted));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Check for permission
if (!bluetoothAlreadyGranted.booleanValue()) {
bluetoothAlreadyGranted = ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.BLUETOOTH_CONNECT);
// Check for permission
if (bluetoothAlreadyGranted.booleanValue()) {
new AlertDialog.Builder(MainApp.getCurrentActivity(), R.style.AppCompatAlertDialogStyle)
.setTitle(activity.getString(R.string.bluetooth_connect_rational_title,
activity.getString(R.string.app_name_flavor)))
.setMessage(activity.getString(R.string.bluetooth_connect_rational_message,
activity.getString(R.string.app_name_flavor)))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.BLUETOOTH_CONNECT},
PERMISSIONS_REQUEST_BLUETOOTH_CONNECT);
}
})
.create()
.show();
} else {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.BLUETOOTH_CONNECT},
PERMISSIONS_REQUEST_BLUETOOTH_CONNECT);
}
} else {
permitted = true;
}
} else {
permitted = true;
}
return permitted;
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
// Check if permission was granted
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; //#TODO you need to check which permission from the array to get the granted status for the matched request code...
switch (requestCode) {
case PERMISSIONS_REQUEST_BLUETOOTH_CONNECT: {
//do whatever you want here
}
break;
}
}
In the Android manifest, the following entry shall be provided:
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
The same shall apply for the dangerous Manifest.permission.BLUETOOTH_SCAN permission with a different intent request code.
I know there are many questions answered regarding checking and requesting permission and handling their response and I am clear on that. But what I bit confuse about is if we are checking for same permission for two different things, how do we continue task after permission is granted?
For example,I have recycleView and in my adapter I have code for two buttons, one would save file and another one would save and open activity to share that file with other app.
MyRecycleAdapter {
Context context:
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(checkPermission()) {
have permission
save file to disk
} else {
requestPermission
save file to disk
}
}
});
share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(checkPermission()) {
have permission
save file to disk
open share activity using (context)
} else {
requestPermission
save file to disk
open share activity using (context)
}
}
});
}
Use different request codes to control what happens after permission is granted:
final int SAVE = 1;
final int SAVE_AND_SHARE = 2;
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
new String[]{
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
},
[either SAVE or SAVE_AND_SHARE]);
} else {
//permission is already granted, continue
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[]
grantResults) {
if (requestCode == SAVE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
//save
} else {
//permission was denied
}
} else if (requestCode == SAVE_AND_SHARE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
//save and share
} else {
//permission was denied
}
}
}
Just for the sake of completion. Requesting permissions has been simplified lately in the API. Here's how I check for a permission before doing some action:
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Permission callback
val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
// Yay, permission was granted
doSomething()
}
else {
// Boo, permission was refused
Snackbar.make(root,"Wut ?! We need your permission!", Snackbar.LENGTH_LONG).show()
}
}
}
private fun checkLocationPermissionAndDoSomething() {
// Do we have the permission ?
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// Permission is not granted. Should we show an explanation?
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
// Explanation is needed. Show dialog
val builder = AlertDialog.Builder(requireContext())
builder.setTitle("Please")
builder.setMessage("We need to use your location because bla blah bla.")
builder.setPositiveButton(android.R.string.ok) { _, _ ->
requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
builder.show()
}
else {
// No explanation needed, we can request the permission.
requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
} else {
// Permission has already been granted
doSomething()
}
}
When multiple permissions are needed just use ActivityResultContracts.RequestMultiplePermissions and use an array of permissions
I am doing an application to scan barcodes on a button click and it was working fine up to Lollipop versions. When I came to Marshmallow it stopped working. This is the error:
camerabase an error occurred while connecting to camera 0
It forces me to turn on permission by:
Settings --> application --> my app --> camera.
My question is how to allow camera permission to my app automatically in Marshmallow or by asking the user to turn on camera at runtime. A screen shot:
Below I have written a code for granting a runtime permissions for Camera, There is an Array of String in which you can give multiple requests granting as which is needed at runtime.
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 200;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkPermission()) {
//main logic or main code
// . write your main code to execute, It will execute if the permission is already given.
} else {
requestPermission();
}
}
private boolean checkPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
return false;
}
return true;
}
private void requestPermission() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
PERMISSION_REQUEST_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(getApplicationContext(), "Permission Granted", Toast.LENGTH_SHORT).show();
// main logic
} else {
Toast.makeText(getApplicationContext(), "Permission Denied", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
showMessageOKCancel("You need to allow access permissions",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermission();
}
}
});
}
}
}
break;
}
}
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(MainActivity.this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
}
}
This is the complete code to implement multiple or single runtime permissions
Step 1
Add permission in manifest for camera and also other required
permissions
like
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Step 2
declare this variable
public static final int REQUEST_ID_MULTIPLE_PERMISSIONS= 7;
and Call this method checkAndroidVersion() in oncreate()
private void checkAndroidVersion() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkAndRequestPermissions();
} else {
// code for lollipop and pre-lollipop devices
}
}
private boolean checkAndRequestPermissions() {
int camera = ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.CAMERA);
int wtite = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
int read = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE);
List<String> listPermissionsNeeded = new ArrayList<>();
if (wtite != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (camera != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CAMERA);
}
if (read != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(getActivity(), listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
Log.d("in fragment on request", "Permission callback called-------");
switch (requestCode) {
case REQUEST_ID_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<>();
// Initialize the map with both permissions
perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.READ_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for both permissions
if (perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED && perms.get(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d("in fragment on request", "CAMERA & WRITE_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE permission granted");
// process the normal flow
//else any one or both the permissions are not granted
} else {
Log.d("in fragment on request", "Some permissions are not granted ask again ");
//permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
// // shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)) {
showDialogOK("Camera and Storage Permission required for this app",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
break;
}
}
});
}
//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
Toast.makeText(getActivity(), "Go to settings and enable permissions", Toast.LENGTH_LONG)
.show();
// //proceed with logic by disabling the related features or quit the app.
}
}
}
}
}
}
private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(getActivity())
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
}
if (ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity)
getContext(), Manifest.permission.CAMERA)) {
} else {
ActivityCompat.requestPermissions((Activity) getContext(),
new String[]{Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA);
}
}
This sample Profile project demonstrates how to get Read Storage and Camera Permission in Android and also how to handle when the user selects DENY & DON'T ASK AGAIN.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
registerStoragePermission()
registerGalleryLauncher()
registerCameraPermission()
registerCameraLauncher()
}
private fun registerCameraPermission() {
requestCameraPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
Log.d(TAG, "registerCameraPermission - Camera Permission Granted")
openCamera()
} else {
Log.d(TAG, "registerCameraPermission - Camera Permission NOT Granted")
requestCameraPermission()
}
}
}
private fun registerStoragePermission() {
requestStoragePermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
Log.d(TAG, "registerStoragePermission - Storage Permission Granted")
viewGallery()
} else {
Log.d(TAG, "registerStoragePermission - Storage Permission NOT Granted")
requestStoragePermission()
}
}
}
private fun registerCameraLauncher() {
cameraLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
if (data == null) {
return#registerForActivityResult
}
val extras = data.extras
imageBitmap = extras!!["data"] as Bitmap
file = FileUtils.createFile(requireContext(),
getString(R.string.app_name),
"my_profile_image.png"
)
//FileUtils.saveBitmap(imageBitmap, file);
val imageLocalPath = FileUtils.saveImageToInternalStorage(file, imageBitmap)
SharedPreferencesUtils.setProfilePath(requireActivity(), imageLocalPath)
profileFragmentBinding.imageViewCircleNoStroke.setImageBitmap(imageBitmap)
profileFragmentBinding.imageViewCircleNoStroke.setScaleType(ImageView.ScaleType.CENTER_CROP)
}
}
}
private fun registerGalleryLauncher() {
galleryLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
if (data == null) {
return#registerForActivityResult
}
val uri = data.data
var imageLocalPath = File(FileUtils.getPathReal(requireActivity(), uri!!))
file = imageLocalPath.absoluteFile
SharedPreferencesUtils.setProfilePath(requireActivity(), imageLocalPath.absolutePath)
Glide.with(requireActivity()).load(uri)
.into(profileFragmentBinding.imageViewCircleNoStroke)
profileFragmentBinding.imageViewCircleNoStroke.setScaleType(ImageView.ScaleType.CENTER_CROP)
}
}
}
private fun showImageUploadOptions() {
val mDialog = activity.let { Dialog(it!!) }
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
mDialog.setContentView(R.layout.dialog_profile_image_option)
mDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
//val mAlertMessageTv = mDialog.findViewById<View>(R.id.id_alert_tv) as TextView
//mAlertMessageTv.text = message
galleryLl = mDialog.findViewById<View>(R.id.id_gallery_ll) as LinearLayout
cameraLl = mDialog.findViewById<View>(R.id.id_camera_ll) as LinearLayout
removePhotoLl = mDialog.findViewById<View>(R.id.id_remove_photo_ll) as LinearLayout
galleryLl.setOnClickListener {
CallStoragePermission()
mDialog.dismiss()
}
cameraLl.setOnClickListener {
CallCameraPermission()
mDialog.dismiss()
}
removePhotoLl.setOnClickListener {
CallRemovePhoto()
mDialog.dismiss()
}
mDialog.setCancelable(true)
mDialog.show()
val metrics = resources.displayMetrics
val width = metrics.widthPixels
val height = metrics.heightPixels
mDialog.window!!.setLayout(
width,
LinearLayout.LayoutParams.WRAP_CONTENT
)
}
fun CallStoragePermission() {
if (!Status_checkReadExternalStoragePermission()) {
requestStoragePermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
} else {
viewGallery()
}
}
private fun Status_checkReadExternalStoragePermission(): Boolean {
val permissionState = ActivityCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.READ_EXTERNAL_STORAGE
)
return permissionState == PackageManager.PERMISSION_GRANTED
}
private fun requestCameraPermission() {
when {
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
Log.d(TAG, "requestCameraPermission - Camera Permission Granted")
openCamera()
// The permission is granted
// you can go with the flow that requires permission here
}
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
// This case means user previously denied the permission
// So here we can display an explanation to the user
// That why exactly we need this permission
Log.d(TAG, "requestCameraPermission - Camera Permission NOT Granted")
showPermissionAlert(
getString(R.string.camera_permission),
getString(R.string.camera_permission_denied),
getString(R.string.ok_caps),
getString(R.string.cancel_caps)
) { requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA) }
}
else -> {
// Everything is fine you can simply request the permission
showPermissionAlert(
getString(R.string.camera_permission),
getString(R.string.camera_permission_denied),
getString(R.string.settings_caps),
getString(R.string.cancel_caps)
) {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID, null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
}
}
}
private fun requestStoragePermission() {
when {
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED -> {
Log.d(TAG, "requestStoragePermission - Storage Permission Granted")
viewGallery()
// The permission is granted
// you can go with the flow that requires permission here
}
shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE) -> {
// This case means user previously denied the permission
// So here we can display an explanation to the user
// That why exactly we need this permission
Log.d(TAG, "requestStoragePermission - Storage Permission NOT Granted")
showPermissionAlert(
getString(R.string.read_storage_permission_required),
getString(R.string.storage_permission_denied),
getString(R.string.ok_caps),
getString(R.string.cancel_caps)
) { requestStoragePermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) }
}
else -> {
// Everything is fine you can simply request the permission
showPermissionAlert(
getString(R.string.read_storage_permission_required),
getString(R.string.storage_permission_denied),
getString(R.string.settings_caps),
getString(R.string.cancel_caps)
) {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID, null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
}
}
}
private fun showPermissionAlert(
title: String,
message: String,
ok: String,
cancel: String,
function: () -> Unit
) {
val mDialog = requireActivity().let { Dialog(it) }
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
mDialog.setContentView(R.layout.dialog_permission_alert)
mDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val mTitleTv = mDialog.findViewById<View>(R.id.id_title_tv) as AppCompatTextView
mTitleTv.text = title
val mMessageTv = mDialog.findViewById<View>(R.id.id_message_tv) as AppCompatTextView
mMessageTv.text = message
val mNoBtn = mDialog.findViewById<View>(R.id.no_btn) as AppCompatTextView
mNoBtn.text = cancel
val mYesBtn = mDialog.findViewById<View>(R.id.yes_btn) as AppCompatTextView
mYesBtn.text = ok
mYesBtn.setOnClickListener {
function.invoke()
mDialog.dismiss()
}
mNoBtn.setOnClickListener { mDialog.dismiss() }
mDialog.setCancelable(true)
mDialog.show()
val metrics = resources.displayMetrics
val width = metrics.widthPixels
val height = metrics.heightPixels
mDialog.window!!.setLayout(
width,
LinearLayout.LayoutParams.WRAP_CONTENT
)
}
fun viewGallery() {
val intentDocument = Intent(Intent.ACTION_GET_CONTENT)
intentDocument.type = "image/*"
intentDocument.putExtra(
Constants.REQUEST_CODE,
Constants.REQUEST_PHOTO_FROM_GALLERY
)
galleryLauncher.launch(intentDocument)
}
fun openCamera() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
takePictureIntent.putExtra(
Constants.REQUEST_CODE,
Constants.REQUEST_PERMISSIONS_REQUEST_CODE_CAMERA
)
cameraLauncher.launch(takePictureIntent)
}
fun CallCameraPermission() {
if (!Status_checkCameraPermission()) {
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
} else {
openCamera()
}
}
private fun Status_checkCameraPermission(): Boolean {
val camera = ActivityCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.CAMERA
)
return camera == PackageManager.PERMISSION_GRANTED
}
RxPermission is best library for asking permissions from user.
For camera permission the workaround is like this.
1) First add these permissions (or one you need) in your manifest.xml.
<uses-permission android:name="android.permission.CAMERA" />
2) Then ask run time permission from user in your activity.
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.CAMERA) // 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?
Manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
Call it somewhere in your activity:
handlePermissions(new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
});
Also in your activity:
private void handlePermissions(String[] permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ArrayList<String> notGrantedPerms = new ArrayList<>();
for (String p : permissions) {
if (this.checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED)
notGrantedPerms.add(p);
}
permissions = notGrantedPerms.toArray(new String[0]);
if (permissions != null && permissions.length > 0)
this.requestPermissions(permissions, 701);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 701) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String p : permissions) {
String msg = "";
if (this.checkSelfPermission(p) == PackageManager.PERMISSION_GRANTED)
msg = "Permission Granted for " + p;
else
msg = "Permission not Granted for " + p;
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
}
}
void AutoRequestAllPermissions(){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M){return;}
PackageInfo info = null;
try {
info = getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
if(info==null){return;}
String[] permissions = info.requestedPermissions;
boolean remained = false;
for (String permission : permissions) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
remained = true;
}
}
if(remained) {
requestPermissions(permissions, 0);
}
}
this code-
automatically read all permissions from manifest
then check if any permission is not granted
then request that remaining permissions
This might help:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
{
if(ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.CAMERA))
{
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
alertBuilder.setCancelable(true);
alertBuilder.setTitle("Permission necessary");
alertBuilder.setMessage("CAMERA is necessary");
alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions((Activity) context,
new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUESTS);
}
});
AlertDialog alert = alertBuilder.create();
alert.show();
} else {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUESTS);
}
return false;
} else {
return true;
}
Where MY_PERMISSIONS_REQUESTS is your final value of the request code.
It works just fine for me.
After having it defined in your manifest file, a friendlier alternative to the native solution would be using Aaper: https://github.com/LikeTheSalad/aaper like so:
#EnsurePermissions(permissions = [Manifest.permission.CAMERA])
private fun takePhoto() {
// Your code that needs the camera permission granted.
}
Disclaimer, I'm the creator of Aaper.
Android team has provided a new way in requesting permissions using registerForActivityResult,
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Define an object to request permissions, and receive the result in the
callback
private val requestPermissionsLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions.all { it.value }) {
Toast.makeText(
this,
"You have obtained the required permissions",
Toast.LENGTH_LONG
).show()
} else Toast.makeText(
this,
"You have not accepted all the permissions",
Toast.LENGTH_LONG
).show()
}
To ask for the permissions, do the following, you can add wherever you think is better:
requestPermissionsLauncher.launch(
arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
)
In Lollipop, the download functionality works fine in my app, but when I upgraded to Marshmallow, my app crashes and gives this error when I try to download from the internet into the SD card:
Neither user nor current process has android.permission.WRITE_EXTERNAL_STORAGE
It complains about this line of code:
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
I have the permissions in the manifest outside application:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
I cleaned and rebuilt the project, but it still crashes.
You should be checking if the user has granted permission of external storage by using:
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
//File write logic here
return true;
}
If not, you need to ask the user to grant your app a permission:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
Of course these are for marshmallow devices only so you need to check if your app is running on Marshmallow:
if (Build.VERSION.SDK_INT >= 23) {
//do your check here
}
Be also sure that your activity implements OnRequestPermissionResult
The entire permission looks like this:
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
return true;
} else {
Log.v(TAG,"Permission is revoked");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG,"Permission is granted");
return true;
}
}
Permission result callback:
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
//resume tasks needing this permission
}
}
Android's permission system is one of the biggest security concern all
along since those permissions are asked for at install time. Once
installed, the application will be able to access all of things
granted without any user's acknowledgement what exactly application
does with the permission.
Android 6.0 Marshmallow introduces one of the largest changes to the
permissions model with the addition of runtime permissions, a new
permission model that replaces the existing install time permissions
model when you target API 23 and the app is running on an Android 6.0+
device
Courtesy goes to Requesting Permissions at Run Time .
Example
Declare this as Global
private static final int PERMISSION_REQUEST_CODE = 1;
Add this in your onCreate() section
After setContentView(R.layout.your_xml);
if (Build.VERSION.SDK_INT >= 23)
{
if (checkPermission())
{
// Code for above or equal 23 API Oriented Device
// Your Permission granted already .Do next code
} else {
requestPermission(); // Code for permission
}
}
else
{
// Code for Below 23 API Oriented Device
// Do next code
}
Now adding checkPermission() and requestPermission()
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
private void requestPermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(Your_Activity.this, "Write External Storage permission allows us to do store images. Please allow this permission in App Settings.", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(Your_Activity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.e("value", "Permission Granted, Now you can use local drive .");
} else {
Log.e("value", "Permission Denied, You cannot use local drive .");
}
break;
}
}
FYI
onRequestPermissionsResult
This interface is the contract for receiving the results for
permission requests.
Check multiple Permission in API level 23
Step 1:
String[] permissions = new String[]{
Manifest.permission.INTERNET,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.VIBRATE,
Manifest.permission.RECORD_AUDIO,
};
Step 2:
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(this, p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), 100);
return false;
}
return true;
}
Step 3:
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == 100) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// do something
}
return;
}
}
Step 4:
in onCreate of Activity
checkPermissions();
Unless there is a definite requirement of writing on external storage, you can always choose to save files in app directory. In my case I had to save files and after wasting 2 to 3 days I found out if I change the storage path from
Environment.getExternalStorageDirectory()
to
getApplicationContext().getFilesDir().getPath() //which returns the internal app files directory path
it works like charm on all the devices.
This is because for writing on External storage you need extra permissions but writing in internal app directory is simple.
you need to use runtime permission in marshmallow
https://developer.android.com/training/permissions/requesting.html
you can check in app info -> permission
is your app get permission for write external storage or not
From marshmallow version, developers need to ask for runtime permissions to user.
Let me give you whole process for asking runtime permissions.
I am using reference from here : marshmallow runtime permissions android.
First create a method which checks whether all permissions are given or not
private boolean checkAndRequestPermissions() {
int camerapermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
int writepermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permissionLocation = ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION);
int permissionRecordAudio = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
List<String> listPermissionsNeeded = new ArrayList<>();
if (camerapermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CAMERA);
}
if (writepermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (permissionLocation != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (permissionRecordAudio != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.RECORD_AUDIO);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
Now here is the code which is run after above method. We will override onRequestPermissionsResult() method :
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
Log.d(TAG, "Permission callback called-------");
switch (requestCode) {
case REQUEST_ID_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<>();
// Initialize the map with both permissions
perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for both permissions
if (perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "sms & location services permission granted");
// process the normal flow
Intent i = new Intent(MainActivity.this, WelcomeActivity.class);
startActivity(i);
finish();
//else any one or both the permissions are not granted
} else {
Log.d(TAG, "Some permissions are not granted ask again ");
//permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
// // shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
showDialogOK("Service Permissions are required for this app",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
finish();
break;
}
}
});
}
//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
explain("You need to give some mandatory permissions to continue. Do you want to go to app settings?");
// //proceed with logic by disabling the related features or quit the app.
}
}
}
}
}
}
If user clicks on Deny option then showDialogOK() method will be used to show dialog
If user clicks on Deny and also clicks a checkbox saying "never ask again", then explain() method will be used to show dialog.
methods to show dialogs :
private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
}
private void explain(String msg){
final android.support.v7.app.AlertDialog.Builder dialog = new android.support.v7.app.AlertDialog.Builder(this);
dialog.setMessage(msg)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
// permissionsclass.requestPermission(type,code);
startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:com.exampledemo.parsaniahardik.marshmallowpermission")));
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
finish();
}
});
dialog.show();
}
Above code snippet asks for four permissions at a time. You can also ask for any number of permissions in your any activity as per your requirements.
The easiest way I found was
private boolean checkPermissions(){
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
return true;
}
else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_CODE);
return false;
}
}
Add below code to your OnCreate() function in MainAcitivity, which will display pop up to ask for permission:
if (ActivityCompat.shouldShowRequestPermissionRationale(TestActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)){
}
else {
ActivityCompat.requestPermissions(TestActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Log.d(TAG, "Permission granted");
} else {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
fab.setOnClickListener(v -> {
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.refer_pic);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/*");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(requireActivity().getContentResolver(),
b, "Title", null);
Uri imageUri = Uri.parse(path);
share.putExtra(Intent.EXTRA_STREAM, imageUri);
share.putExtra(Intent.EXTRA_TEXT, "Here is text");
startActivity(Intent.createChooser(share, "Share via"));
});
After lots of searching This code work for me:
Check the permission already has:
Check WRITE_EXTERNAL_STORAGE permission Allowed or not?
if(isReadStorageAllowed()){
//If permission is already having then showing the toast
//Toast.makeText(SplashActivity.this,"You already have the permission",Toast.LENGTH_LONG).show();
//Existing the method with return
return;
}else{
requestStoragePermission();
}
private boolean isReadStorageAllowed() {
//Getting the permission status
int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
//If permission is granted returning true
if (result == PackageManager.PERMISSION_GRANTED)
return true;
//If permission is not granted returning false
return false;
}
//Requesting permission
private void requestStoragePermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)){
//If the user has denied the permission previously your code will come to this block
//Here you can explain why you need this permission
//Explain here why you need this permission
}
//And finally ask for the permission
ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_STORAGE);
}
Implement Override onRequestPermissionsResult method for checking is the user allow or denie
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
//Checking the request code of our request
if(requestCode == REQUEST_WRITE_STORAGE){
//If permission is granted
if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
//Displaying a toast
Toast.makeText(this,"Permission granted now you can read the storage",Toast.LENGTH_LONG).show();
}else{
//Displaying another toast if permission is not granted
Toast.makeText(this,"Oops you just denied the permission",Toast.LENGTH_LONG).show();
}
}
Before starting your download check your runtime permissions and if you don't have permission the request permissions like this method
requestStoragePermission()
private void requestStoragePermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.READ_EXTERNAL_STORAGE))
{
}
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
STORAGE_PERMISSION_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults) {
if(requestCode == STORAGE_PERMISSION_CODE){
if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
}
else{
Toast.makeText(this,
"Oops you just denied the permission",
Toast.LENGTH_LONG).show();
}
}
}
In a simple way the permission can be granted using manifest.xml file, but it was ok till the api level 23 sdk version 6, after from here, if we want to get the permission we have to ask for the use to allow the permission which are needed.
Just add this code in the mainActivity.java
Override
public void onClick(View view) {
// Request the permission
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA},
PERMISSION_REQUEST_CAMERA);
Replace CAMERA or add with WRITE_EXTERNAL_STORAGE if you want, and with the unique code.
new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
101);
This is the simple code to get permission.
When I have a target API of 23 on Android M Preview 3, I cannot seem to acquire the Manifest.permission.WRITE_SETTTINGS permission.
requestPermissions(new String[]{Manifest.permission.WRITE_SETTINGS}, 101);
Request permission doesn't bring up the dialog I would expect, but if I make the following call without this permission,
RingtoneManager.setActualDefaultRingtoneUri(activity, RingtoneManager.TYPE_RINGTONE, ringUri);
The call will except because I don't have the permission.
I'm not sure where to go from here. Is there a new ringtone API for 23? Or did this permission change just make it impossible for any non-system apps to change the ringtone?
To use WRITE_SETTINGS, based on the docs:
Have the <uses-permission> element in the manifest as normal.
Call Settings.System.canWrite() to see if you are eligible to write out settings.
If canWrite() returns false, start up the ACTION_MANAGE_WRITE_SETTINGS activity so the user can agree there to allow your app to actually write to settings.
In other words, writing to settings is now a double-opt-in (agree to install, agree separately in Settings to allow), akin to device admin APIs, accessibility services, etc.
Also note that I have not tried using these yet — this is based on research that I did yesterday on Android 6.0 changes.
In addition to the answer from CommonsWare and the comment from Ogix, here is some dummy code:
private boolean checkSystemWritePermission() {
boolean retVal = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
retVal = Settings.System.canWrite(this);
Log.d(TAG, "Can Write Settings: " + retVal);
if(retVal){
Toast.makeText(this, "Write allowed :-)", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this, "Write not allowed :-(", Toast.LENGTH_LONG).show();
FragmentManager fm = getFragmentManager();
PopupWritePermission dialogFragment = new PopupWritePermission();
dialogFragment.show(fm, getString(R.string.popup_writesettings_title));
}
}
return retVal;
}
The Fragment PopupwritePermission then gives a window where the situation is explained. A click on the OK Button will open the Android System Menu where the Permission can be granted:
private void openAndroidPermissionsMenu() {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
startActivity(intent);
}
The previous answers are great, I have just little addition for also getting the result for the permission asking.
public static void youDesirePermissionCode(Activity context){
boolean permission;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
permission = Settings.System.canWrite(context);
} else {
permission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED;
}
if (permission) {
//do your code
} else {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivityForResult(intent, MainActivity.CODE_WRITE_SETTINGS_PERMISSION);
} else {
ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_SETTINGS}, MainActivity.CODE_WRITE_SETTINGS_PERMISSION);
}
}
}
And then in the Activity:
#SuppressLint("NewApi")
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MainActivity.CODE_WRITE_SETTINGS_PERMISSION && Settings.System.canWrite(this)){
Log.d("TAG", "MainActivity.CODE_WRITE_SETTINGS_PERMISSION success");
//do your code
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == MainActivity.CODE_WRITE_SETTINGS_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//do your code
}
}
This is a complete example:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.System.canWrite(context) {
// Do stuff here
}
else {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
As of android Marshmellow , you require to use runtime permissions which aims to more security , or use permission when need here is documenatation
and for Write Settings documentation is here
In manifest add
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
In your class
private boolean checkSystemWritePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(Settings.System.canWrite(context))
return true;
else
openAndroidPermissionsMenu();
}
return false;
}
private void openAndroidPermissionsMenu() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
}
}
And use it like this
try {
if (checkSystemWritePermission()) {
RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, newUri);
Toast.makeText(context, "Set as ringtoon successfully ", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context, "Allow modify system settings ==> ON ", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.i("ringtoon",e.toString());
Toast.makeText(context, "unable to set as Ringtoon ", Toast.LENGTH_SHORT).show();
}
The permission android.permission.WRITE_SETTINGS is now in the group signature|appop|pre23|preinstalled like android.permission.CHANGE_NETWORK_STATE and android.permission.SYSTEM_ALERT_WINDOW
This means you get it on sdk 22 and below. On newer version you have to be an app operator.
I have used bellow like..
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
boolean retVal = true;
retVal = Settings.System.canWrite(this);
if (retVal == false) {
if (!Settings.System.canWrite(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
Toast.makeText(getApplicationContext(), "Please, allow system settings for automatic logout ", Toast.LENGTH_LONG).show();
startActivityForResult(intent, 200);
}
}else {
Toast.makeText(getApplicationContext(), "You are not allowed to wright ", Toast.LENGTH_LONG).show();
}
}
Manifest permission
<uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" />
• Kotlin Version in Simple Steps
Follow these steps:
1. Add the permission's usage element in the manifest.xml normally:
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
2. Where you want to change the settings, check the write access:
if (context.canWriteSettings) {
// change the settings here ...
} else {
startManageWriteSettingsPermission()
}
3. Also add these lines of code in case of requesting the permission:
private fun startManageWriteSettingsPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent(
Settings.ACTION_MANAGE_WRITE_SETTINGS,
Uri.parse("package:${context.packageName}")
).let {
startActivityForResult(it, REQUEST_CODE_WRITE_SETTINGS_PERMISSION)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_WRITE_SETTINGS_PERMISSION -> {
if (context.canWriteSettings) {
// change the settings here ...
} else {
Toast.makeText(context, "Write settings permission is not granted!", Toast.LENGTH_SHORT).show()
}
}
}
}
val Context.canWriteSettings: Boolean
get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.System.canWrite(this)
companion object {
private const val REQUEST_CODE_WRITE_SETTINGS_PERMISSION = 5
}
Mention below permission in AndroidManifest.xml
In Activity use below if else for changing setting.
if(Settings.System.canWrite(this)){
// change setting here
}
else{
//Migrate to Setting write permission screen.
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + mContext.getPackageName()));
startActivity(intent);
}
In my case i have solved by this way.:
public void checkSystemWriteSettings(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(context)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + context.getApplicationInfo().packageName));
startActivity(intent);
}else
{
Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 10);
}
}
}