No se puede obtener el permiso WRITE_SETTINGS

Cuando tengo una API objective de 23 en Android M Preview 3, parece que no puedo obtener el permiso Manifest.permission.WRITE_SETTTINGS.

requestPermissions(new String[]{Manifest.permission.WRITE_SETTINGS}, 101); 

El permiso de solicitud no abre el diálogo que esperaría, pero si realizo la siguiente llamada sin este permiso,

  RingtoneManager.setActualDefaultRingtoneUri(activity, RingtoneManager.TYPE_RINGTONE, ringUri); 

La llamada se realizará excepto porque no tengo el permiso.

No estoy seguro de a dónde ir desde aquí. ¿Hay una nueva API de tono de llamada para 23? ¿O ha cambiado este permiso solo hace que sea imposible para cualquier aplicación que no sea del sistema cambiar el tono de llamada?

Para usar WRITE_SETTINGS , basado en los documentos:

  1. Tener el elemento en el manifiesto como normal.

  2. Llame a Settings.System.canWrite() para ver si es elegible para escribir configuraciones.

  3. Si canWrite() devuelve false , inicie la actividad ACTION_MANAGE_WRITE_SETTINGS para que el usuario pueda aceptar que su aplicación realmente escriba en la configuración.

IOW, al escribir en la configuración ahora es una opción doble (acepte instalar, acuerde por separado en Configuración para permitir), similar a las API de administración del dispositivo, los servicios de accesibilidad, etc.

También tenga en cuenta que no he intentado usar estos todavía – esto se basa en la investigación que hice ayer sobre los cambios de Android 6.0 .

Como complemento a la respuesta de CommonsWare, y el comentario de Ogix, aquí un código falso

 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; } 

El Fragmento PopupwritePermission da entonces una ventana donde se explica la situación. Al hacer clic en el botón Aceptar se abrirá el menú del sistema de Android donde se puede otorgar el permiso:

 private void openAndroidPermissionsMenu() { Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); intent.setData(Uri.parse("package:" + getActivity().getPackageName())); startActivity(intent); } 

Las respuestas anteriores son geniales, solo tengo una pequeña adición para obtener el resultado de la solicitud de permiso.

  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); } } } 

Y luego en la 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 } } 

Este es un ejemplo completo:

 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); } } 

El permiso android.permission.WRITE_SETTINGS ahora está en la signature|appop|pre23|preinstalled del grupo signature|appop|pre23|preinstalled como android.permission.CHANGE_NETWORK_STATE y android.permission.SYSTEM_ALERT_WINDOW

Esto significa que lo obtiene en sdk 22 y abajo. En la versión más nueva, debes ser un operador de aplicaciones.

Mencione el permiso debajo en AndroidManifest.xml

En la actividad use a continuación para cambiar la configuración.

 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); } 

A partir de Android Marshmellow, necesita utilizar permisos de tiempo de ejecución que apuntan a más seguridad, o use permiso cuando sea necesario documenatation

y para la documentación de Configuración de escritura está aquí

En manifiesto agregar

  

En tu clase

 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); } } 

Y úsalo así

 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(); }