Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Permissões com Headless Fragment

Permissões com Headless Fragment

Slides do talk apresentado no Android Dev Conference 2017 (pt-br)

Rafael Araujo

August 25, 2017
Tweet

More Decks by Rafael Araujo

Other Decks in Programming

Transcript

  1. Todos na mesma página... Android 6.0 (Marshmallow - API level

    23) Recursos específicos em run time Segurança Responsabilidade do desenvolvedor garantir o recurso na hora correta 3
  2. Tirando uma foto class MainCurrentWayActivity : AppCompatActivity() { override fun

    onCreate(savedInstanceState: Bundle?) { findViewById(R.id.activity_main_camera) .setOnClickListener { takeAPic() } } fun takeAPic() {} } 4
  3. Usuário clicou para tirar uma foto findViewById(R.id.activity_main_camera).setOnClickListener { val permissionCheck

    = ContextCompat.checkSelfPermission(this, CAMERA) if (permissionCheck == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { ActivityCompat.requestPermissions(this, arrayOf(CAMERA), PERMISSION_RC) } } 5
  4. Usuário clicou para tirar uma foto findViewById(R.id.activity_main_camera).setOnClickListener { val permissionCheck

    = ContextCompat.checkSelfPermission(this, CAMERA) if (permissionCheck == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { ActivityCompat.requestPermissions(this, arrayOf(CAMERA), PERMISSION_RC) } } 6
  5. Usuário clicou para tirar uma foto findViewById(R.id.activity_main_camera).setOnClickListener { val permissionCheck

    = ContextCompat.checkSelfPermission(this, CAMERA) if (permissionCheck == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { ActivityCompat.requestPermissions(this, arrayOf(CAMERA), PERMISSION_RC) } } 7
  6. Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:

    Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 9
  7. Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:

    Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 10
  8. Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:

    Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 11
  9. Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:

    Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 12
  10. Headless Fragment Fragments sem UI (sem inflar um XML) Reter

    objetos grandes demais para o Bundle da Activity Lógica isolada da camada View Reutilizar em outras telas 16
  11. Em arquiteturas VIEW VIEW MVP MVVM MODEL MODEL PRESENTER VIEW

    MODEL Headless Fragment Headless Fragment 18
  12. Activity class MainNewWayActivity : AppCompatActivity(), PermissionListener { override fun onCreate(savedInstanceState:

    Bundle?) { findViewById(R.id.activity_main_camera).setOnClickListener { val helper: PermissionHelper = PermissionHelper() helper.requestPermissionIfNeeded(supportFragmentManager) } } override fun onPermissionGranted() { takeAPic() } override fun onPermissionDenied() { finish() } } 30
  13. Activity class MainNewWayActivity : AppCompatActivity(), PermissionListener { override fun onCreate(savedInstanceState:

    Bundle?) { findViewById(R.id.activity_main_camera).setOnClickListener { val helper: PermissionHelper = PermissionHelper() helper.requestPermissionIfNeeded(supportFragmentManager) } } override fun onPermissionGranted() { takeAPic() } override fun onPermissionDenied() { finish() } } 31
  14. Activity class MainNewWayActivity : AppCompatActivity(), PermissionListener { override fun onCreate(savedInstanceState:

    Bundle?) { findViewById(R.id.activity_main_camera).setOnClickListener { val helper: PermissionHelper = PermissionHelper() helper.requestPermissionIfNeeded(supportFragmentManager) } } override fun onPermissionGranted() { takeAPic() } override fun onPermissionDenied() { finish() } } 32
  15. Headless Fragment class PermissionHelper : DialogFragment() { override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) isCancelable = false } } 33
  16. Headless Fragment class PermissionHelper : DialogFragment() { override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) isCancelable = false } } 34
  17. Configurando o Callback private lateinit var mListener: PermissionListener override fun

    onAttach(context: Context?) { super.onAttach(context) if (context is PermissionListener) { mListener = context } } 35
  18. Configurando o Callback private lateinit var mListener: PermissionListener override fun

    onAttach(context: Context?) { super.onAttach(context) if (context is PermissionListener) { mListener = context } } 36
  19. Configurando o Callback private fun onPermissionGranted() { dismiss() mListener.onPermissionGranted() }

    private fun onPermissionDenied() { dismiss() mListener.onPermissionDenied() } 37
  20. Método público private val PERMISSION_TAG = "PERMISSION_TAG" fun requestPermissionIfNeeded(fragmentManager: FragmentManager)

    { val fragment = fragmentManager.findFragmentByTag(PERMISSION_TAG) if (fragment == null) { show(fragmentManager, PERMISSION_TAG) } } 38
  21. Requisitando a permissão private val PERMISSIONS = arrayOf(permission.CAMERA, permission.RECORD_AUDIO) private

    val PERMISSION_RC = 100 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestPermissions(PERMISSIONS, PERMISSION_RC) } 39
  22. Requisitando a permissão private val PERMISSIONS = arrayOf(permission.CAMERA, permission.RECORD_AUDIO) private

    val PERMISSION_RC = 100 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestPermissions(PERMISSIONS, PERMISSION_RC) } 40
  23. Flags de contole private var mCheckPermissionStatus: Boolean = false private

    var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 42
  24. Flags de contole private var mCheckPermissionStatus: Boolean = false private

    var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 43
  25. Flags de contole private var mCheckPermissionStatus: Boolean = false private

    var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 44
  26. OnResume chamado após onCreate override fun onResume() { if (mCheckPermissionStatus

    && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 45
  27. OnResume chamado após onCreate override fun onResume() { if (mCheckPermissionStatus

    && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 46
  28. override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i

    in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 48
  29. override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i

    in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 49
  30. Reinicia todas as flags de controle private fun resetFlags() {

    mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 50
  31. Reinicia todas as flags de controle private fun resetFlags() {

    mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 51
  32. Reinicia todas as flags de controle private fun resetFlags() {

    mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 52
  33. override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i

    in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 53
  34. override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i

    in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 54
  35. override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i

    in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 55
  36. override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i

    in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 56
  37. override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i

    in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 57
  38. OnResume chamado após ação do usuário override fun onResume() {

    if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 59
  39. Todas permissão foram aceitas? override fun onResume() { if (mCheckPermissionStatus

    && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 60
  40. Alguma permissão foi negada override fun onResume() { if (mCheckPermissionStatus

    && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 61
  41. Negou sem "Não perguntar novamente" override fun onResume() { if

    (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 62
  42. Tentar novamente através de uma dialog private fun showRetryDialog() {

    alert("Para continuar é necessário aceitar as permissões") { titleResource = "Permissão recusada" positiveButton("OK") { requestPermissions(PERMISSIONS, PERMISSION_RC) } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 63
  43. Recomeça o fluxo novamente private fun showRetryDialog() { alert("Para continuar

    é necessário aceitar as permissões") { titleResource = "Permissão recusada" positiveButton("OK") { requestPermissions(PERMISSIONS, PERMISSION_RC) } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 64
  44. Callback negativo para a View private fun showRetryDialog() { alert("Para

    continuar é necessário aceitar as permissões") { titleResource = "Permissão recusada" positiveButton("OK") { requestPermissions(PERMISSIONS, PERMISSION_REQUEST_CODE) } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 65
  45. Negou com "Não perguntar novamente" override fun onResume() { if

    (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 67
  46. Enviando para Configurações do Aplicativo private fun showAppSettingDialog() { alert("Conceda

    as permissões nas configurações do aplicativo") { titleResource = "Permissão necessária" positiveButton("OK") { showAppSettings() } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 68
  47. Envia usuário para as configurações private fun showAppSettingDialog() { alert("Conceda

    as permissões nas configurações do aplicativo") { titleResource = "Permissão necessária" positiveButton("OK") { showAppSettings() } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 69
  48. Callback negativo para a Activity private fun showAppSettingDialog() { alert("Conceda

    as permissões nas configurações do aplicativo") { titleResource = "Permissão necessária" positiveButton("OK") { showAppSettings() } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 70
  49. Além do apresentado... Parametrização Permissões e mensangens por parâmetro Dagger

    ​ Facilidade na injeção de demais classes Escopo por Activity RxJava para Callbacks Verificar conexão com Headless Fragment 73