Home | History | Annotate | Download | only in runtimepermissions
      1 /*
      2 * Copyright 2015 The Android Open Source Project
      3 *
      4 * Licensed under the Apache License, Version 2.0 (the "License");
      5 * you may not use this file except in compliance with the License.
      6 * You may obtain a copy of the License at
      7 *
      8 *     http://www.apache.org/licenses/LICENSE-2.0
      9 *
     10 * Unless required by applicable law or agreed to in writing, software
     11 * distributed under the License is distributed on an "AS IS" BASIS,
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 * See the License for the specific language governing permissions and
     14 * limitations under the License.
     15 */
     16 
     17 package com.example.android.system.runtimepermissions;
     18 
     19 import android.Manifest;
     20 import android.app.Activity;
     21 import android.content.Context;
     22 import android.content.pm.PackageManager;
     23 import android.os.Bundle;
     24 import android.support.annotation.NonNull;
     25 import android.support.design.widget.Snackbar;
     26 import android.support.v4.app.ActivityCompat;
     27 import android.support.v4.app.FragmentTransaction;
     28 import android.support.v7.app.AppCompatActivity;
     29 import android.util.Log;
     30 import android.view.View;
     31 
     32 import com.example.android.system.runtimepermissions.camera.CameraPreviewFragment;
     33 import com.example.android.system.runtimepermissions.contacts.ContactsFragment;
     34 
     35 /**
     36  * Launcher Activity that demonstrates the use of runtime permissions for Android M.
     37  * It contains a summary sample description, sample log and a Fragment that calls callbacks on this
     38  * Activity to illustrate parts of the runtime permissions API.
     39  * <p>
     40  * This Activity requests permissions to access the camera ({@link android.Manifest.permission#CAMERA})
     41  * when the 'Show Camera' button is clicked to display the camera preview.
     42  * Contacts permissions (({@link android.Manifest.permission#READ_CONTACTS} and ({@link
     43  * android.Manifest.permission#WRITE_CONTACTS})) are requested when the 'Show and Add Contacts'
     44  * button is
     45  * clicked to display the first contact in the contacts database and to add a dummy contact
     46  * directly to it. Permissions are verified and requested through compat helpers in the support v4
     47  * library, in this Activity using {@link ActivityCompat}.
     48  * First, permissions are checked if they have already been granted through {@link
     49  * ActivityCompat#checkSelfPermission(Context, String)}.
     50  * If permissions have not been granted, they are requested through
     51  * {@link ActivityCompat#requestPermissions(Activity, String[], int)} and the return value checked
     52  * in
     53  * a callback to the {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback}
     54  * interface.
     55  * <p>
     56  * Before requesting permissions, {@link ActivityCompat#shouldShowRequestPermissionRationale(Activity,
     57  * String)}
     58  * should be called to provide the user with additional context for the use of permissions if they
     59  * have been denied previously.
     60  * <p>
     61  * If this sample is executed on a device running a platform version below M, all permissions
     62  * declared
     63  * in the Android manifest file are always granted at install time and cannot be requested at run
     64  * time.
     65  * <p>
     66  * This sample targets the M platform and must therefore request permissions at runtime. Change the
     67  * targetSdk in the file 'Application/build.gradle' to 22 to run the application in compatibility
     68  * mode.
     69  * Now, if a permission has been disable by the system through the application settings, disabled
     70  * APIs provide compatibility data.
     71  * For example the camera cannot be opened or an empty list of contacts is returned. No special
     72  * action is required in this case.
     73  * <p>
     74  * (This class is based on the MainActivity used in the SimpleFragment sample template.)
     75  */
     76 public class MainActivity extends AppCompatActivity
     77         implements ActivityCompat.OnRequestPermissionsResultCallback {
     78 
     79     public static final String TAG = "MainActivity";
     80 
     81     /**
     82      * Id to identify a camera permission request.
     83      */
     84     private static final int REQUEST_CAMERA = 0;
     85 
     86     /**
     87      * Id to identify a contacts permission request.
     88      */
     89     private static final int REQUEST_CONTACTS = 1;
     90 
     91     /**
     92      * Permissions required to read and write contacts. Used by the {@link ContactsFragment}.
     93      */
     94     private static String[] PERMISSIONS_CONTACT = {Manifest.permission.READ_CONTACTS,
     95             Manifest.permission.WRITE_CONTACTS};
     96 
     97     /**
     98      * Root of the layout of this Activity.
     99      */
    100     private View mLayout;
    101 
    102     /**
    103      * Called when the 'show camera' button is clicked.
    104      * Callback is defined in resource layout definition.
    105      */
    106     public void showCamera(View view) {
    107         Log.i(TAG, "Show camera button pressed. Checking permission.");
    108         // BEGIN_INCLUDE(camera_permission)
    109         // Check if the Camera permission is already available.
    110         if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
    111                 != PackageManager.PERMISSION_GRANTED) {
    112             // Camera permission has not been granted.
    113 
    114             requestCameraPermission();
    115 
    116         } else {
    117 
    118             // Camera permissions is already available, show the camera preview.
    119             Log.i(TAG,
    120                     "CAMERA permission has already been granted. Displaying camera preview.");
    121             showCameraPreview();
    122         }
    123         // END_INCLUDE(camera_permission)
    124 
    125     }
    126 
    127     /**
    128      * Requests the Camera permission.
    129      * If the permission has been denied previously, a SnackBar will prompt the user to grant the
    130      * permission, otherwise it is requested directly.
    131      */
    132     private void requestCameraPermission() {
    133         Log.i(TAG, "CAMERA permission has NOT been granted. Requesting permission.");
    134 
    135         // BEGIN_INCLUDE(camera_permission_request)
    136         if (ActivityCompat.shouldShowRequestPermissionRationale(this,
    137                 Manifest.permission.CAMERA)) {
    138             // Provide an additional rationale to the user if the permission was not granted
    139             // and the user would benefit from additional context for the use of the permission.
    140             // For example if the user has previously denied the permission.
    141             Log.i(TAG,
    142                     "Displaying camera permission rationale to provide additional context.");
    143             Snackbar.make(mLayout, R.string.permission_camera_rationale,
    144                     Snackbar.LENGTH_INDEFINITE)
    145                     .setAction(R.string.ok, new View.OnClickListener() {
    146                         @Override
    147                         public void onClick(View view) {
    148                             ActivityCompat.requestPermissions(MainActivity.this,
    149                                     new String[]{Manifest.permission.CAMERA},
    150                                     REQUEST_CAMERA);
    151                         }
    152                     })
    153                     .show();
    154         } else {
    155 
    156             // Camera permission has not been granted yet. Request it directly.
    157             ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
    158                     REQUEST_CAMERA);
    159         }
    160         // END_INCLUDE(camera_permission_request)
    161     }
    162 
    163     /**
    164      * Called when the 'show camera' button is clicked.
    165      * Callback is defined in resource layout definition.
    166      */
    167     public void showContacts(View v) {
    168         Log.i(TAG, "Show contacts button pressed. Checking permissions.");
    169 
    170         // Verify that all required contact permissions have been granted.
    171         if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
    172                 != PackageManager.PERMISSION_GRANTED
    173                 || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS)
    174                 != PackageManager.PERMISSION_GRANTED) {
    175             // Contacts permissions have not been granted.
    176             Log.i(TAG, "Contact permissions has NOT been granted. Requesting permissions.");
    177             requestContactsPermissions();
    178 
    179         } else {
    180 
    181             // Contact permissions have been granted. Show the contacts fragment.
    182             Log.i(TAG,
    183                     "Contact permissions have already been granted. Displaying contact details.");
    184             showContactDetails();
    185         }
    186     }
    187 
    188     /**
    189      * Requests the Contacts permissions.
    190      * If the permission has been denied previously, a SnackBar will prompt the user to grant the
    191      * permission, otherwise it is requested directly.
    192      */
    193     private void requestContactsPermissions() {
    194         // BEGIN_INCLUDE(contacts_permission_request)
    195         if (ActivityCompat.shouldShowRequestPermissionRationale(this,
    196                 Manifest.permission.READ_CONTACTS)
    197                 || ActivityCompat.shouldShowRequestPermissionRationale(this,
    198                 Manifest.permission.WRITE_CONTACTS)) {
    199 
    200             // Provide an additional rationale to the user if the permission was not granted
    201             // and the user would benefit from additional context for the use of the permission.
    202             // For example, if the request has been denied previously.
    203             Log.i(TAG,
    204                     "Displaying contacts permission rationale to provide additional context.");
    205 
    206             // Display a SnackBar with an explanation and a button to trigger the request.
    207             Snackbar.make(mLayout, R.string.permission_contacts_rationale,
    208                     Snackbar.LENGTH_INDEFINITE)
    209                     .setAction(R.string.ok, new View.OnClickListener() {
    210                         @Override
    211                         public void onClick(View view) {
    212                             ActivityCompat
    213                                     .requestPermissions(MainActivity.this, PERMISSIONS_CONTACT,
    214                                             REQUEST_CONTACTS);
    215                         }
    216                     })
    217                     .show();
    218         } else {
    219             // Contact permissions have not been granted yet. Request them directly.
    220             ActivityCompat.requestPermissions(this, PERMISSIONS_CONTACT, REQUEST_CONTACTS);
    221         }
    222         // END_INCLUDE(contacts_permission_request)
    223     }
    224 
    225 
    226     /**
    227      * Display the {@link CameraPreviewFragment} in the content area if the required Camera
    228      * permission has been granted.
    229      */
    230     private void showCameraPreview() {
    231         getSupportFragmentManager().beginTransaction()
    232                 .replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
    233                 .addToBackStack("contacts")
    234                 .commit();
    235     }
    236 
    237     /**
    238      * Display the {@link ContactsFragment} in the content area if the required contacts
    239      * permissions
    240      * have been granted.
    241      */
    242     private void showContactDetails() {
    243         getSupportFragmentManager().beginTransaction()
    244                 .replace(R.id.sample_content_fragment, ContactsFragment.newInstance())
    245                 .addToBackStack("contacts")
    246                 .commit();
    247     }
    248 
    249 
    250     /**
    251      * Callback received when a permissions request has been completed.
    252      */
    253     @Override
    254     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
    255             @NonNull int[] grantResults) {
    256 
    257         if (requestCode == REQUEST_CAMERA) {
    258             // BEGIN_INCLUDE(permission_result)
    259             // Received permission result for camera permission.
    260             Log.i(TAG, "Received response for Camera permission request.");
    261 
    262             // Check if the only required permission has been granted
    263             if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    264                 // Camera permission has been granted, preview can be displayed
    265                 Log.i(TAG, "CAMERA permission has now been granted. Showing preview.");
    266                 Snackbar.make(mLayout, R.string.permision_available_camera,
    267                         Snackbar.LENGTH_SHORT).show();
    268             } else {
    269                 Log.i(TAG, "CAMERA permission was NOT granted.");
    270                 Snackbar.make(mLayout, R.string.permissions_not_granted,
    271                         Snackbar.LENGTH_SHORT).show();
    272 
    273             }
    274             // END_INCLUDE(permission_result)
    275 
    276         } else if (requestCode == REQUEST_CONTACTS) {
    277             Log.i(TAG, "Received response for contact permissions request.");
    278 
    279             // We have requested multiple permissions for contacts, so all of them need to be
    280             // checked.
    281             if (PermissionUtil.verifyPermissions(grantResults)) {
    282                 // All required permissions have been granted, display contacts fragment.
    283                 Snackbar.make(mLayout, R.string.permision_available_contacts,
    284                         Snackbar.LENGTH_SHORT)
    285                         .show();
    286             } else {
    287                 Log.i(TAG, "Contacts permissions were NOT granted.");
    288                 Snackbar.make(mLayout, R.string.permissions_not_granted,
    289                         Snackbar.LENGTH_SHORT)
    290                         .show();
    291             }
    292 
    293         } else {
    294             super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    295         }
    296     }
    297 
    298     public void onBackClick(View view) {
    299         getSupportFragmentManager().popBackStack();
    300     }
    301 
    302     @Override
    303     protected void onCreate(Bundle savedInstanceState) {
    304         super.onCreate(savedInstanceState);
    305         setContentView(R.layout.activity_main);
    306         mLayout = findViewById(R.id.sample_main_layout);
    307         if (savedInstanceState == null) {
    308             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    309             RuntimePermissionsFragment fragment = new RuntimePermissionsFragment();
    310             transaction.replace(R.id.sample_content_fragment, fragment);
    311             transaction.commit();
    312         }
    313     }
    314 }
    315