SlideShare uma empresa Scribd logo
1 de 76
Baixar para ler offline
Permissões com
Headless Fragment
1
Rafael Araujo
Android Developer Sênior
Campinas - SP, Brasil
2
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
Tirando uma foto
class MainCurrentWayActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
findViewById(R.id.activity_main_camera)
.setOnClickListener { takeAPic() }
}
fun takeAPic() {}
}
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)
}
}
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)
}
}
6
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
Requisitando
a permissão
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()
}
}
}
} 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()
}
}
}
} 10
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
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
Caso usuário
negar...
13
Alguns problemas
Lógica na view
​Muito código
Lidar com muitos fluxos
​Boilerplate
14
Proposta? Headless Fragment!
15
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
Em arquiteturas
VIEWVIEW
MVP MVVM
MODEL MODEL
PRESENTER VIEW MODEL
17
Em arquiteturas
VIEWVIEW
MVP MVVM
MODEL MODEL
PRESENTER VIEW MODEL
Headless
Fragment
Headless
Fragment
18
Isolando o código
View
Headless
Fragment
19
Isolando o código
View
Headless
Fragment
Permissão concedida?
20
Isolando o código
View
Headless
Fragment
Permissão concedida?
Permitiu ou Negou
21
Fácil reutilização
View
Model
ViewModel
Timeline
View
Model
ViewModel
Perfil
View
Model
ViewModel
Chat
22
Fácil reutilização
View
Model
ViewModel
Permissão
Câmera
Timeline
View
Model
ViewModel
Perfil
View
Model
ViewModel
Chat
23
Entendo o porque um Fragment
onCreate()Inicio onResume() onPause()onAttach()
24
Requisitando a permissão
...
requestPermissions()
onResume() onPause()
25
Resultado da permissão
...
requestPermissions()
onResume() onPause()
onRequestPermissionsResult()
26
Resultado da permissão
...
requestPermissions()
onResume() onPause()
onRequestPermissionsResult()
27
Talk is cheap, show me the code!
28
Callbacks
public interface PermissionListener {
​ void onPermissionGranted();
void onPermissionDenied();
}
29
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
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
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
Headless Fragment
class PermissionHelper : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
isCancelable = false
}
}
33
Headless Fragment
class PermissionHelper : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
isCancelable = false
}
}
34
Configurando o Callback
private lateinit var mListener: PermissionListener
override fun onAttach(context: Context?) {
super.onAttach(context)
if (context is PermissionListener) {
mListener = context
}
}
35
Configurando o Callback
private lateinit var mListener: PermissionListener
override fun onAttach(context: Context?) {
super.onAttach(context)
if (context is PermissionListener) {
mListener = context
}
}
36
Configurando o Callback
private fun onPermissionGranted() {
dismiss()
mListener.onPermissionGranted()
}
private fun onPermissionDenied() {
dismiss()
mListener.onPermissionDenied()
}
37
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
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
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
Resultado da permissão
...
requestPermissions()
onResume() onPause()
onRequestPermissionsResult()
41
Flags de contole
private var mCheckPermissionStatus: Boolean = false
private var mAcceptedAll: Boolean = false
private var mShouldRetry: Boolean = false
private var mExternalRequestRequired: Boolean = false
42
Flags de contole
private var mCheckPermissionStatus: Boolean = false
private var mAcceptedAll: Boolean = false
private var mShouldRetry: Boolean = false
private var mExternalRequestRequired: Boolean = false
43
Flags de contole
private var mCheckPermissionStatus: Boolean = false
private var mAcceptedAll: Boolean = false
private var mShouldRetry: Boolean = false
private var mExternalRequestRequired: Boolean = false
44
OnResume chamado após onCreate
override fun onResume() {
if (mCheckPermissionStatus && mAcceptedAll) {
onPermissionGranted()
} else {
if (mShouldRetry) {
showRetryDialog()
} else if (mExternalRequestRequired) {
showAppSettingDialog()
}
}
}
45
OnResume chamado após onCreate
override fun onResume() {
if (mCheckPermissionStatus && mAcceptedAll) {
onPermissionGranted()
} else {
if (mShouldRetry) {
showRetryDialog()
} else if (mExternalRequestRequired) {
showAppSettingDialog()
}
}
}
46
Requisitando
a permissão
47
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
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
Reinicia todas as flags de controle
private fun resetFlags() {
mCheckPermissionStatus = true
mAcceptedAll = false
mShouldRetry = false
mExternalRequestRequired = false
}
50
Reinicia todas as flags de controle
private fun resetFlags() {
mCheckPermissionStatus = true
mAcceptedAll = false
mShouldRetry = false
mExternalRequestRequired = false
}
51
Reinicia todas as flags de controle
private fun resetFlags() {
mCheckPermissionStatus = true
mAcceptedAll = false
mShouldRetry = false
mExternalRequestRequired = false
}
52
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
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
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
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
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
Resultado da permissão
...
requestPermissions()
onResume() onPause()
onRequestPermissionsResult()
58
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
Todas permissão foram aceitas?
override fun onResume() {
if (mCheckPermissionStatus && mAcceptedAll) {
onPermissionGranted()
} else {
if (mShouldRetry) {
showRetryDialog()
} else if (mExternalRequestRequired) {
showAppSettingDialog()
}
}
}
60
Alguma permissão foi negada
override fun onResume() {
if (mCheckPermissionStatus && mAcceptedAll) {
onPermissionGranted()
} else {
if (mShouldRetry) {
showRetryDialog()
} else if (mExternalRequestRequired) {
showAppSettingDialog()
}
}
}
61
Negou sem "Não perguntar novamente"
override fun onResume() {
if (mCheckPermissionStatus && mAcceptedAll) {
onPermissionGranted()
} else {
if (mShouldRetry) {
showRetryDialog()
} else if (mExternalRequestRequired) {
showAppSettingDialog()
}
}
}
62
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
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
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
Dialog de tentar
novamente
66
Negou com "Não perguntar novamente"
override fun onResume() {
if (mCheckPermissionStatus && mAcceptedAll) {
onPermissionGranted()
} else {
if (mShouldRetry) {
showRetryDialog()
} else if (mExternalRequestRequired) {
showAppSettingDialog()
}
}
}
67
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
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
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
Permissões nas
configurações
71
Fluxo
completo
72
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
/oRafaAraujo
/androidDevConference2017
74
Slides WEB:
slides.com/orafaeldearaujo/permissoes-com-headless-fragment
75
Obrigado!
@orafaaraujo
/in/rafaeldearaujo
/orafaaraujo
76

Mais conteúdo relacionado

Semelhante a Permissoes com Headless Fragment

Teste unitário
Teste unitárioTeste unitário
Teste unitáriodist_bp
 
TDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no AndroidTDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no Androidtdc-globalcode
 
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014David Robert Camargo de Campos
 
Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010rafaelferreira
 
Privilégios de processos no OpenSolaris
Privilégios de processos no OpenSolarisPrivilégios de processos no OpenSolaris
Privilégios de processos no OpenSolarisRafael Barbolo
 
Demoiselle Behave - Parte 2
Demoiselle Behave - Parte 2Demoiselle Behave - Parte 2
Demoiselle Behave - Parte 2Vanderson Silva
 
Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Elton Minetto
 
Testes automatizados
Testes automatizadosTestes automatizados
Testes automatizadosRodrigo Maia
 
Desvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor AndroidDesvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor Androidjoaobmonteiro
 

Semelhante a Permissoes com Headless Fragment (14)

Codifique melhor
Codifique melhorCodifique melhor
Codifique melhor
 
Teste unitário
Teste unitárioTeste unitário
Teste unitário
 
TDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no AndroidTDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no Android
 
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
 
HTML5 Sensitivo
HTML5 SensitivoHTML5 Sensitivo
HTML5 Sensitivo
 
Mock Objects
Mock ObjectsMock Objects
Mock Objects
 
Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010
 
Privilégios de processos no OpenSolaris
Privilégios de processos no OpenSolarisPrivilégios de processos no OpenSolaris
Privilégios de processos no OpenSolaris
 
Tracking.js
Tracking.jsTracking.js
Tracking.js
 
Vraptor
VraptorVraptor
Vraptor
 
Demoiselle Behave - Parte 2
Demoiselle Behave - Parte 2Demoiselle Behave - Parte 2
Demoiselle Behave - Parte 2
 
Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Introdução ao Zend Framework 2
Introdução ao Zend Framework 2
 
Testes automatizados
Testes automatizadosTestes automatizados
Testes automatizados
 
Desvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor AndroidDesvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor Android
 

Permissoes com Headless Fragment

  • 2. Rafael Araujo Android Developer Sênior Campinas - SP, Brasil 2
  • 3. 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
  • 4. Tirando uma foto class MainCurrentWayActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { findViewById(R.id.activity_main_camera) .setOnClickListener { takeAPic() } } fun takeAPic() {} } 4
  • 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) } } 5
  • 6. 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
  • 7. 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
  • 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() } } } } 9
  • 10. 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
  • 11. 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
  • 12. 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
  • 14. Alguns problemas Lógica na view ​Muito código Lidar com muitos fluxos ​Boilerplate 14
  • 16. 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
  • 17. Em arquiteturas VIEWVIEW MVP MVVM MODEL MODEL PRESENTER VIEW MODEL 17
  • 18. Em arquiteturas VIEWVIEW MVP MVVM MODEL MODEL PRESENTER VIEW MODEL Headless Fragment Headless Fragment 18
  • 21. Isolando o código View Headless Fragment Permissão concedida? Permitiu ou Negou 21
  • 24. Entendo o porque um Fragment onCreate()Inicio onResume() onPause()onAttach() 24
  • 26. Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 26
  • 27. Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 27
  • 28. Talk is cheap, show me the code! 28
  • 29. Callbacks public interface PermissionListener { ​ void onPermissionGranted(); void onPermissionDenied(); } 29
  • 30. 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
  • 31. 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
  • 32. 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
  • 33. Headless Fragment class PermissionHelper : DialogFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) isCancelable = false } } 33
  • 34. Headless Fragment class PermissionHelper : DialogFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) isCancelable = false } } 34
  • 35. Configurando o Callback private lateinit var mListener: PermissionListener override fun onAttach(context: Context?) { super.onAttach(context) if (context is PermissionListener) { mListener = context } } 35
  • 36. Configurando o Callback private lateinit var mListener: PermissionListener override fun onAttach(context: Context?) { super.onAttach(context) if (context is PermissionListener) { mListener = context } } 36
  • 37. Configurando o Callback private fun onPermissionGranted() { dismiss() mListener.onPermissionGranted() } private fun onPermissionDenied() { dismiss() mListener.onPermissionDenied() } 37
  • 38. 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
  • 39. 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
  • 40. 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
  • 41. Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 41
  • 42. Flags de contole private var mCheckPermissionStatus: Boolean = false private var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 42
  • 43. Flags de contole private var mCheckPermissionStatus: Boolean = false private var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 43
  • 44. Flags de contole private var mCheckPermissionStatus: Boolean = false private var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 44
  • 45. OnResume chamado após onCreate override fun onResume() { if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 45
  • 46. OnResume chamado após onCreate override fun onResume() { if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 46
  • 48. 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
  • 49. 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
  • 50. Reinicia todas as flags de controle private fun resetFlags() { mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 50
  • 51. Reinicia todas as flags de controle private fun resetFlags() { mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 51
  • 52. Reinicia todas as flags de controle private fun resetFlags() { mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 52
  • 53. 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
  • 54. 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
  • 55. 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
  • 56. 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
  • 57. 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
  • 58. Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 58
  • 59. 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
  • 60. Todas permissão foram aceitas? override fun onResume() { if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 60
  • 61. Alguma permissão foi negada override fun onResume() { if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 61
  • 62. Negou sem "Não perguntar novamente" override fun onResume() { if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 62
  • 63. 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
  • 64. 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
  • 65. 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
  • 67. Negou com "Não perguntar novamente" override fun onResume() { if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 67
  • 68. 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
  • 69. 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
  • 70. 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
  • 73. 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