10

Poiché l'SDK 23 di Android offre agli utenti la possibilità di negare l'accesso ad alcune funzionalità, volevo aggiornare una delle mie app per richiedere le autorizzazioni come descritto qui: https://developer.android.com/preview/features/runtime-permissions.html.Richiesta di autorizzazione duplicata dopo il cambio di orientamento

In una delle attività ho incorporato uno SupportMapFragment. Per farlo funzionare è necessario disporre dell'autorizzazione WRITE_EXTERNAL_STORAGE, quindi lo richiedo quando avvio l'attività che risulta in una creazione di una finestra di dialogo di richiesta di autorizzazione.

Ora il problema è che quando la finestra di dialogo è ancora aperta e ruoto il dispositivo, l'attività verrà riavviata e aprirà una nuova finestra di dialogo di richiesta di autorizzazione mentre quella precedente è ancora lì. Il risultato sono due di questi dialoghi uno sopra l'altro e solo uno di essi è utile.

C'è un modo per sbarazzarsi della finestra di dialogo che è stata avviata prima?

+4

Poiché non hai creato il dialogo, non sono a conoscenza di alcun modo per te di sbarazzartene. Metti un 'boolean' nello stato di istanza salvato' Bundle' che indica che la richiesta di autorizzazione è in sospeso e non richiedi nuovamente l'autorizzazione. Oppure, attendi di richiedere l'autorizzazione fino a quando non invii qualche tipo di input dell'utente (ad esempio, toccando l'elemento della barra delle azioni che lancia il 'SupportMapFragment'), nel qual caso dovresti essere sicuro, poiché l'utente non può toccare di nuovo quell'elemento mentre la finestra di dialogo è visibile. – CommonsWare

+0

Sì, è così. Non pensavo che sarebbe stata un'opzione in quanto la "vecchia" finestra di dialogo sarebbe stata legata solo alla "vecchia" attività, ma l'ho appena provata e il risultato è stato ricevuto dalla "nuova" attività. – Thorben

risposta

11

Come dichiarato da CommonsWare nel suo comment, la soluzione migliore è inserire un valore booleano nel pacchetto SavedInstanceState per sapere se la finestra di dialogo è ancora aperta.

Esempio:

// true if dialog already open 
private boolean alreadyAskedForStoragePermission = false; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    if(savedInstanceState != null) { 
     alreadyAskedForStoragePermission = savedInstanceState.getBoolean(STORAGE_PERMISSION_DIALOG_OPEN_KEY, false); 
    } 
} 

@Override 
protected void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 

    outState.putBoolean(KEY, alreadyAskedForStoragePermission); 
} 

private void checkStoragePermission(){ 
    if(alreadyAskedForStoragePermission){ 
     // don't check again because the dialog is still open 
     return; 
    } 

    if(ActivityCompat.checkSelfPermission(this, STORAGE_PERMISSIONS[0]) != PackageManager.PERMISSION_GRANTED){ 
     // the dialog will be opened so we have to keep that in memory 
     alreadyAskedForStoragePermission = true; 
     ActivityCompat.requestPermissions(this, STORAGE_PERMISSIONS, STORAGE_PERMISSION_REQUEST_CODE); 
    } else { 
     onStoragePermissionGranted(); 
    } 
} 

@Override 
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 
    switch (requestCode){ 
     case STORAGE_PERMISSION_REQUEST_CODE: 
      // the request returned a result so the dialog is closed 
      alreadyAskedForStoragePermission = false; 

      if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ 
       onStoragePermissionGranted(); 
      } 

      break; 
    } 
} 
+0

Credo che esista un sistema booleano in bundle savedInstanceState android: hasCurrentPermissionsRequest = true se viene mostrata la finestra di dialogo delle autorizzazioni, sebbene non abbia trovato alcun riferimento nella documentazione. – user1991776

0

Suppongo che poiché si tratta di una finestra di dialogo di sistema, non è possibile controllarla. Potresti invece impedire che la tua attività venga ricaricata se giri il tuo dispositivo.

8

Come @ user1991776 menzionato v'è in realtà un extra non documentata che contiene se non c'è un dialogo permesso aperto al momento, in Activity:

private static final String HAS_CURENT_PERMISSIONS_REQUEST_KEY = 
     "android:hasCurrentPermissionsRequest"; 

Tuttavia c'è un modo migliore. Quando si richiede un dialogo per la seconda volta (a causa di una rotazione) il permesso, Activity annulla automaticamente la vecchia finestra di dialogo chiamando il vostro onRequestPermissionResult()with empty arrays:

public final void requestPermissions(@NonNull String[] permissions, int requestCode) { 
    if (mHasCurrentPermissionsRequest) { 
     Log.w(TAG, "Can reqeust only one set of permissions at a time"); 
     // Dispatch the callback with empty arrays which means a cancellation. 
     onRequestPermissionsResult(requestCode, new String[0], new int[0]); 
     return; 
    } 
    Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions); 
    startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null); 
    mHasCurrentPermissionsRequest = true; 
} 

O corso questo comportamento isn't documented perché questo è Android, e che vuole documentare comportamento complesso?

In ogni caso è sempre possibile richiedere le autorizzazioni in onCreate() e quindi ignorare le chiamate a onRequestPermissionsResult() con gli array di lunghezza zero permissions.

+0

+ per documentazione android =) –