1616
1717package com .example .android .system .runtimepermissions ;
1818
19- import com .example .android .common .activities .SampleActivityBase ;
2019import com .example .android .common .logger .Log ;
2120import com .example .android .common .logger .LogFragment ;
2221import com .example .android .common .logger .LogWrapper ;
2625
2726import android .Manifest ;
2827import android .app .Activity ;
28+ import android .content .Context ;
2929import android .content .pm .PackageManager ;
3030import android .os .Bundle ;
31+ import android .support .annotation .NonNull ;
32+ import android .support .design .widget .Snackbar ;
33+ import android .support .v4 .app .ActivityCompat ;
3134import android .support .v4 .app .FragmentTransaction ;
3235import android .view .Menu ;
3336import android .view .MenuItem ;
3437import android .view .View ;
35- import android .widget .Toast ;
3638import android .widget .ViewAnimator ;
3739
40+ import common .activities .SampleActivityBase ;
41+
3842/**
3943 * Launcher Activity that demonstrates the use of runtime permissions for Android M.
4044 * It contains a summary sample description, sample log and a Fragment that calls callbacks on this
4650 * android.Manifest.permission#WRITE_CONTACTS})) are requested when the 'Show and Add Contacts'
4751 * button is
4852 * clicked to display the first contact in the contacts database and to add a dummy contact
49- * directly
50- * to it. First, permissions are checked if they have already been granted through {@link
51- * android.app.Activity#checkSelfPermission(String)} (wrapped in {@link
52- * PermissionUtil#hasSelfPermission(Activity, String)} and {@link PermissionUtil#hasSelfPermission(Activity,
53- * String[])} for compatibility). If permissions have not been granted, they are requested through
54- * {@link Activity#requestPermissions(String[], int)} and the return value checked in {@link
55- * Activity#onRequestPermissionsResult(int, String[], int[])}.
53+ * directly to it. Permissions are verified and requested through compat helpers in the support v4
54+ * library, in this Activity using {@link ActivityCompat}.
55+ * First, permissions are checked if they have already been granted through {@link
56+ * ActivityCompat#checkSelfPermission(Context, String)}.
57+ * If permissions have not been granted, they are requested through
58+ * {@link ActivityCompat#requestPermissions(Activity, String[], int)} and the return value checked
59+ * in
60+ * a callback to the {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback}
61+ * interface.
5662 * <p>
57- * Before requesting permissions, {@link Activity#shouldShowRequestPermissionRationale(String)}
63+ * Before requesting permissions, {@link ActivityCompat#shouldShowRequestPermissionRationale(Activity,
64+ * String)}
5865 * should be called to provide the user with additional context for the use of permissions if they
5966 * have been denied previously.
6067 * <p>
7380 * <p>
7481 * (This class is based on the MainActivity used in the SimpleFragment sample template.)
7582 */
76- public class MainActivity extends SampleActivityBase {
83+ public class MainActivity extends SampleActivityBase
84+ implements ActivityCompat .OnRequestPermissionsResultCallback {
7785
7886 public static final String TAG = "MainActivity" ;
7987
@@ -96,6 +104,10 @@ public class MainActivity extends SampleActivityBase {
96104 // Whether the Log Fragment is currently shown.
97105 private boolean mLogShown ;
98106
107+ /**
108+ * Root of the layout of this Activity.
109+ */
110+ private View mLayout ;
99111
100112 /**
101113 * Called when the 'show camera' button is clicked.
@@ -105,30 +117,57 @@ public void showCamera(View view) {
105117 Log .i (TAG , "Show camera button pressed. Checking permission." );
106118 // BEGIN_INCLUDE(camera_permission)
107119 // Check if the Camera permission is already available.
108- if (PermissionUtil .hasSelfPermission (this , Manifest .permission .CAMERA )) {
120+ if (ActivityCompat .checkSelfPermission (this , Manifest .permission .CAMERA )
121+ != PackageManager .PERMISSION_GRANTED ) {
122+ // Camera permission has not been granted.
123+
124+ requestCameraPermission ();
125+
126+ } else {
127+
109128 // Camera permissions is already available, show the camera preview.
110129 Log .i (TAG ,
111130 "CAMERA permission has already been granted. Displaying camera preview." );
112131 showCameraPreview ();
113- } else {
114- // Camera permission has not been granted.
115- Log .i (TAG , "CAMERA permission has NOT been granted. Requesting permission." );
132+ }
133+ // END_INCLUDE(camera_permission)
116134
135+ }
136+
137+ /**
138+ * Requests the Camera permission.
139+ * If the permission has been denied previously, a SnackBar will prompt the user to grant the
140+ * permission, otherwise it is requested directly.
141+ */
142+ private void requestCameraPermission () {
143+ Log .i (TAG , "CAMERA permission has NOT been granted. Requesting permission." );
144+
145+ // BEGIN_INCLUDE(camera_permission_request)
146+ if (ActivityCompat .shouldShowRequestPermissionRationale (this ,
147+ Manifest .permission .CAMERA )) {
117148 // Provide an additional rationale to the user if the permission was not granted
118149 // and the user would benefit from additional context for the use of the permission.
119- if (shouldShowRequestPermissionRationale (Manifest .permission .CAMERA )) {
120- Log .i (TAG ,
121- "Displaying camera permission rationale to provide additional context." );
122- Toast .makeText (this , R .string .permission_camera_rationale , Toast .LENGTH_SHORT )
123- .show ();
124- }
150+ // For example if the user has previously denied the permission.
151+ Log .i (TAG ,
152+ "Displaying camera permission rationale to provide additional context." );
153+ Snackbar .make (mLayout , R .string .permission_camera_rationale ,
154+ Snackbar .LENGTH_INDEFINITE )
155+ .setAction (R .string .ok , new View .OnClickListener () {
156+ @ Override
157+ public void onClick (View view ) {
158+ ActivityCompat .requestPermissions (MainActivity .this ,
159+ new String []{Manifest .permission .CAMERA },
160+ REQUEST_CAMERA );
161+ }
162+ })
163+ .show ();
164+ } else {
125165
126- // Request Camera permission
127- requestPermissions (new String []{Manifest .permission .CAMERA },
166+ // Camera permission has not been granted yet. Request it directly.
167+ ActivityCompat . requestPermissions (this , new String []{Manifest .permission .CAMERA },
128168 REQUEST_CAMERA );
129169 }
130- // END_INCLUDE(camera_permission)
131-
170+ // END_INCLUDE(camera_permission_request)
132171 }
133172
134173 /**
@@ -137,30 +176,63 @@ public void showCamera(View view) {
137176 */
138177 public void showContacts (View v ) {
139178 Log .i (TAG , "Show contacts button pressed. Checking permissions." );
179+
140180 // Verify that all required contact permissions have been granted.
141- if (PermissionUtil .hasSelfPermission (this , PERMISSIONS_CONTACT )) {
181+ if (ActivityCompat .checkSelfPermission (this , Manifest .permission .READ_CONTACTS )
182+ != PackageManager .PERMISSION_GRANTED
183+ || ActivityCompat .checkSelfPermission (this , Manifest .permission .WRITE_CONTACTS )
184+ != PackageManager .PERMISSION_GRANTED ) {
185+ // Contacts permissions have not been granted.
186+ Log .i (TAG , "Contact permissions has NOT been granted. Requesting permissions." );
187+ requestContactsPermissions ();
188+
189+ } else {
190+
191+ // Contact permissions have been granted. Show the contacts fragment.
142192 Log .i (TAG ,
143193 "Contact permissions have already been granted. Displaying contact details." );
144- // Contact permissions have been granted. Show the contacts fragment.
145194 showContactDetails ();
146- } else {
147- // Contacts permissions have not been granted.
148- Log .i (TAG , "Contact permissions has NOT been granted. Requesting permission." );
195+ }
196+ }
197+
198+ /**
199+ * Requests the Contacts permissions.
200+ * If the permission has been denied previously, a SnackBar will prompt the user to grant the
201+ * permission, otherwise it is requested directly.
202+ */
203+ private void requestContactsPermissions () {
204+ // BEGIN_INCLUDE(contacts_permission_request)
205+ if (ActivityCompat .shouldShowRequestPermissionRationale (this ,
206+ Manifest .permission .READ_CONTACTS )
207+ || ActivityCompat .shouldShowRequestPermissionRationale (this ,
208+ Manifest .permission .WRITE_CONTACTS )) {
149209
150210 // Provide an additional rationale to the user if the permission was not granted
151211 // and the user would benefit from additional context for the use of the permission.
152- if (shouldShowRequestPermissionRationale (Manifest .permission .CAMERA )) {
153- Log .i (TAG ,
154- "Displaying contacts permission rationale to provide additional context." );
155- Toast .makeText (this , R .string .permission_contacts_rationale , Toast .LENGTH_SHORT )
156- .show ();
157- }
158-
159- // contact permissions has not been granted (read and write contacts). Request them.
160- requestPermissions (PERMISSIONS_CONTACT , REQUEST_CONTACTS );
212+ // For example, if the request has been denied previously.
213+ Log .i (TAG ,
214+ "Displaying contacts permission rationale to provide additional context." );
215+
216+ // Display a SnackBar with an explanation and a button to trigger the request.
217+ Snackbar .make (mLayout , R .string .permission_contacts_rationale ,
218+ Snackbar .LENGTH_INDEFINITE )
219+ .setAction (R .string .ok , new View .OnClickListener () {
220+ @ Override
221+ public void onClick (View view ) {
222+ ActivityCompat
223+ .requestPermissions (MainActivity .this , PERMISSIONS_CONTACT ,
224+ REQUEST_CONTACTS );
225+ }
226+ })
227+ .show ();
228+ } else {
229+ // Contact permissions have not been granted yet. Request them directly.
230+ ActivityCompat .requestPermissions (this , PERMISSIONS_CONTACT , REQUEST_CONTACTS );
161231 }
232+ // END_INCLUDE(contacts_permission_request)
162233 }
163234
235+
164236 /**
165237 * Display the {@link CameraPreviewFragment} in the content area if the required Camera
166238 * permission has been granted.
@@ -189,23 +261,24 @@ private void showContactDetails() {
189261 * Callback received when a permissions request has been completed.
190262 */
191263 @ Override
192- public void onRequestPermissionsResult (int requestCode , String [] permissions ,
193- int [] grantResults ) {
264+ public void onRequestPermissionsResult (int requestCode , @ NonNull String [] permissions ,
265+ @ NonNull int [] grantResults ) {
194266
195267 if (requestCode == REQUEST_CAMERA ) {
196268 // BEGIN_INCLUDE(permission_result)
197269 // Received permission result for camera permission.
198270 Log .i (TAG , "Received response for Camera permission request." );
199271
200272 // Check if the only required permission has been granted
201- if (grantResults [0 ] == PackageManager .PERMISSION_GRANTED ) {
273+ if (grantResults . length == 1 && grantResults [0 ] == PackageManager .PERMISSION_GRANTED ) {
202274 // Camera permission has been granted, preview can be displayed
203275 Log .i (TAG , "CAMERA permission has now been granted. Showing preview." );
204- Toast . makeText ( this , R .string .permision_available_camera , Toast . LENGTH_SHORT )
205- .show ();
276+ Snackbar . make ( mLayout , R .string .permision_available_camera ,
277+ Snackbar . LENGTH_SHORT ) .show ();
206278 } else {
207279 Log .i (TAG , "CAMERA permission was NOT granted." );
208- Toast .makeText (this , R .string .permissions_not_granted , Toast .LENGTH_SHORT ).show ();
280+ Snackbar .make (mLayout , R .string .permissions_not_granted ,
281+ Snackbar .LENGTH_SHORT ).show ();
209282
210283 }
211284 // END_INCLUDE(permission_result)
@@ -217,11 +290,14 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions,
217290 // checked.
218291 if (PermissionUtil .verifyPermissions (grantResults )) {
219292 // All required permissions have been granted, display contacts fragment.
220- Toast .makeText (this , R .string .permision_available_contacts , Toast .LENGTH_SHORT )
293+ Snackbar .make (mLayout , R .string .permision_available_contacts ,
294+ Snackbar .LENGTH_SHORT )
221295 .show ();
222296 } else {
223297 Log .i (TAG , "Contacts permissions were NOT granted." );
224- Toast .makeText (this , R .string .permissions_not_granted , Toast .LENGTH_SHORT ).show ();
298+ Snackbar .make (mLayout , R .string .permissions_not_granted ,
299+ Snackbar .LENGTH_SHORT )
300+ .show ();
225301 }
226302
227303 } else {
@@ -291,6 +367,7 @@ public void onBackClick(View view) {
291367 protected void onCreate (Bundle savedInstanceState ) {
292368 super .onCreate (savedInstanceState );
293369 setContentView (R .layout .activity_main );
370+ mLayout = findViewById (R .id .sample_main_layout );
294371
295372 if (savedInstanceState == null ) {
296373 FragmentTransaction transaction = getSupportFragmentManager ().beginTransaction ();
0 commit comments