1 00:00:05,320 --> 00:00:05,590 Alright, 2 00:00:05,590 --> 00:00:10,600 so we're looking at permissions on Marshmallow and above. The app won't have been granted permission when 3 00:00:10,600 --> 00:00:14,390 it was installed and we have to request permission when the app runs. 4 00:00:14,410 --> 00:00:16,860 So we added a call to check selfPermission in our code, 5 00:00:16,880 --> 00:00:22,570 in the last video, to find out if we have the required permission or not. If the permission hasn't been granted, 6 00:00:22,950 --> 00:00:27,180 and it won't have been the first time the app runs, then we'll get PERMISSION_DENIED 7 00:00:27,430 --> 00:00:29,100 when we call checkSelfPermission. 8 00:00:29,230 --> 00:00:34,870 So that means we have to request the permission in our code. Now this should be fairly straightforward, 9 00:00:35,320 --> 00:00:41,080 except that the users can deny the permission, and they can also tick a box so that they won't be asked 10 00:00:41,080 --> 00:00:42,080 again. 11 00:00:42,100 --> 00:00:46,990 So the flow chart that I'm putting on the screen now shows the options and the various states that our 12 00:00:46,990 --> 00:00:48,730 code has to handle. 13 00:00:48,850 --> 00:00:54,730 So when we check the permission by calling the checkSelfPermission method, we'll automatically be granted the 14 00:00:54,820 --> 00:00:55,710 permission 15 00:00:55,800 --> 00:01:03,250 on devices running API 22 or earlier. So that bit's easy and there's nothing more we need to do. On 16 00:01:03,250 --> 00:01:04,700 API 23 and above 17 00:01:04,700 --> 00:01:08,350 though, we have to request permission from the user. 18 00:01:08,710 --> 00:01:10,660 Now that's still quite straightforward. 19 00:01:10,660 --> 00:01:16,420 If the user grants the permission, then we can proceed and everything's fine, but the user may decide 20 00:01:16,420 --> 00:01:17,710 to deny the permission. 21 00:01:17,800 --> 00:01:24,670 So let's have a look at what they'll see the first time they're asked to grant the permission. Now if the user allows 22 00:01:24,670 --> 00:01:26,780 the permission, then that's fine, 23 00:01:26,950 --> 00:01:32,650 but if they choose to deny it, we have to decide what we're going to do and how we're going to deal with 24 00:01:32,650 --> 00:01:33,940 the situation. 25 00:01:34,030 --> 00:01:39,010 In some apps you could just disable the particular functionality that requires their permission. 26 00:01:39,490 --> 00:01:40,180 In our app 27 00:01:40,230 --> 00:01:42,190 though, that's not really an option. 28 00:01:42,220 --> 00:01:45,130 All the app does is access the contacts records, 29 00:01:45,130 --> 00:01:49,050 and without the necessary permission to do that it's a bit of a pointless app. 30 00:01:49,120 --> 00:01:54,460 It gets slightly more complicated because the next time the app is launched, after the permission has 31 00:01:54,460 --> 00:01:58,050 been denied, the dialogue offers another choice. 32 00:01:58,210 --> 00:02:02,230 So this time there's a box to tick not to be asked again. 33 00:02:02,400 --> 00:02:08,180 So when the user ticks that box, the only option provided is to then deny the permission. 34 00:02:08,220 --> 00:02:13,530 Now that can be a bit confusing to us as developers, and the documentation doesn't make it very clear 35 00:02:13,530 --> 00:02:14,580 unfortunately. 36 00:02:14,850 --> 00:02:19,610 But when they choose to allow the permission then they won't be asked again. 37 00:02:19,810 --> 00:02:25,080 That's automatic once you've allowed the permission, then it remains allowed unless you go into settings 38 00:02:25,080 --> 00:02:31,680 to change it, and we'll have a look at that later. If the user ticks that box and denies the permission, 39 00:02:31,680 --> 00:02:34,200 they won't be asked to allow it again. 40 00:02:34,320 --> 00:02:38,430 So our app just won't get the permission and we have to cater for that in our code. 41 00:02:38,580 --> 00:02:43,320 And once again, some apps could just disable the particular functionality that needs the permission, 42 00:02:43,800 --> 00:02:47,020 but our contacts app becomes useless without it. 43 00:02:47,280 --> 00:02:54,240 So going back to the flowchart, we can see that the situations where permission is granted are easy to 44 00:02:54,240 --> 00:03:00,660 deal with. We'll leave the situations where permission is denied for now, and we'll come back to that once 45 00:03:00,660 --> 00:03:01,750 we've got the app working. 46 00:03:03,480 --> 00:03:09,290 Alright so let's go back to our code now, and the Android framework provides methods to handle requesting 47 00:03:09,290 --> 00:03:11,820 the permission from the user at runtime. 48 00:03:11,840 --> 00:03:17,550 So the first thing we have to do is check the value we got back from calling checkSelfPermission. 49 00:03:17,690 --> 00:03:23,600 So I'm going to add the code and then we'll go through it. So down here after the log, after the hasReadContact 50 00:03:23,600 --> 00:03:24,440 Permission, our 51 00:03:24,810 --> 00:03:26,480 variables, our variable line. 52 00:03:26,570 --> 00:03:33,230 We could add the code if parentheses hasReadContactPermission, 53 00:03:33,230 --> 00:03:44,570 if that's equal to PackageManager.PERMISSION_GRANTED, then we'll open a code block. And there we're going to put log 54 00:03:44,570 --> 00:03:56,580 dot d parentheses TAG comma and we'll just indicate in the message onCreate colon permission granted. And we're going to put 55 00:03:56,840 --> 00:04:00,160 readGranted is equal to true. 56 00:04:00,170 --> 00:04:04,120 However I'm also going to put a comment here TODO 57 00:04:04,790 --> 00:04:09,100 don't do this!! else, 58 00:04:09,300 --> 00:04:13,140 open up a code block Log.d parentheses 59 00:04:13,150 --> 00:04:17,350 TAG comma in double quotes onCreate colon, 60 00:04:17,829 --> 00:04:22,870 and that's requesting permission, because obviously we got denied. 61 00:04:23,240 --> 00:04:25,230 And that's going to be Activity 62 00:04:25,700 --> 00:04:29,410 Compat.requestPermissions 63 00:04:30,020 --> 00:04:30,840 parentheses 64 00:04:30,860 --> 00:04:36,330 this comma space arrayOf parentheses. 65 00:04:36,680 --> 00:04:41,230 Then it's going to be READ_CONTACTS, then a closing right parentheses comma, 66 00:04:41,840 --> 00:04:43,770 then REQUEST underscore 67 00:04:43,790 --> 00:04:44,440 CODE underscore READ 68 00:04:44,450 --> 00:04:46,330 underscore CONTACTS 69 00:04:46,630 --> 00:04:48,520 then closing right parentheses. 70 00:04:48,890 --> 00:04:54,750 And also take this opportunity to log when the onCreate method finishes. So let's add a log call 71 00:04:54,780 --> 00:05:03,730 down there; Log.d parentheses TAG comma onCreate colon ends. 72 00:05:04,270 --> 00:05:09,190 OK, so looking at the code starting on line 32. 73 00:05:09,290 --> 00:05:11,960 So if the result we got back from calling check 74 00:05:11,970 --> 00:05:17,360 SelfPermission was PERMISSION_GRANTED, then we have the permission we need and we can carry on. 75 00:05:17,570 --> 00:05:19,620 We'll need to know that we have the READ 76 00:05:19,620 --> 00:05:25,400 underscore CONTACTS permission later, before we try to access the contacts when the floating action 77 00:05:25,400 --> 00:05:26,500 button's clicked. 78 00:05:26,650 --> 00:05:30,710 So we're storing true in the readGranted field on line 34. 79 00:05:30,710 --> 00:05:34,840 Now we could just call the checkSelfPermission method every time we need to know if the permission's 80 00:05:34,850 --> 00:05:35,450 granted. 81 00:05:35,630 --> 00:05:37,480 But for now I'm going to store the result. 82 00:05:37,490 --> 00:05:41,100 That's a common thing to do but it's often a bad idea. 83 00:05:41,270 --> 00:05:44,020 So I'm going to demonstrate the problems it can cause us later. 84 00:05:44,330 --> 00:05:49,100 So following on from the code though, if the permission wasn't granted, the else codebook is executed starting 85 00:05:49,100 --> 00:05:50,370 on line 36. 86 00:05:50,410 --> 00:05:56,270 So at that point we need to request the permission, and we can do that by using the compat form of 87 00:05:56,270 --> 00:05:59,520 request permissions and you can say that code on line 37. 88 00:05:59,570 --> 00:06:05,420 Once again there's also a method built into the framework, but that'll only work on API 23 and above. 89 00:06:05,960 --> 00:06:11,780 Earlier devices don't know about this new security model, so they have to use the compatibility versions 90 00:06:11,780 --> 00:06:16,120 of those methods from the android.support.v4.app package. 91 00:06:16,220 --> 00:06:21,040 If you're targeting API 23 and above, the code will be almost the same, but you can leave off the 92 00:06:21,040 --> 00:06:26,440 ContextCompat and ActivityCompat class names when calling the methods. 93 00:06:26,510 --> 00:06:31,440 Now I say almost the same, because you don't have to pass this to the framework methods. 94 00:06:31,850 --> 00:06:37,640 The framework checkSelfPermission is called on the context, and request permissions is called on the 95 00:06:37,640 --> 00:06:38,600 activity, 96 00:06:38,600 --> 00:06:44,540 so there's no need to pass this to provide either the context or the activity. The compatible request 97 00:06:44,550 --> 00:06:47,050 permissions method does need to know the activity though, 98 00:06:47,220 --> 00:06:51,010 and that's why the first parameter is this, again on line 37. 99 00:06:51,290 --> 00:06:57,470 So next we provide an array containing the names of the permissions we were requesting. 100 00:06:57,470 --> 00:07:03,170 Now we only want to request a single permission, but it still has to be provided in a string array because 101 00:07:03,170 --> 00:07:04,950 that's the type of the parameter. 102 00:07:04,970 --> 00:07:07,970 You can check that by clicking on the method name and calling up the documentation, 103 00:07:11,210 --> 00:07:13,070 and you can see we've got permissions here; 104 00:07:13,130 --> 00:07:15,950 it's a string array. Now there's quite a lot of description here in 105 00:07:15,950 --> 00:07:20,400 this documentation, so it's well worth a read to understand how it all works. 106 00:07:20,420 --> 00:07:25,520 You may want to read it after we've got this app working though, because we'll be writing the onRequest 107 00:07:25,520 --> 00:07:31,180 PermissionsResult callback method next, and it may make more sense once you've seen that working code. 108 00:07:31,190 --> 00:07:35,830 Also I suggest you read through the guide that I called up in my browser in the last video. 109 00:07:36,080 --> 00:07:41,930 Now the documentation itself can be a bit confusing, and has resulted in some overly complex code on 110 00:07:41,930 --> 00:07:42,810 the Internet. 111 00:07:42,830 --> 00:07:48,170 Earlier versions of the documentation gave the impression that the app had to call requestPermissions 112 00:07:48,260 --> 00:07:49,660 every time it runs, 113 00:07:49,790 --> 00:07:52,200 which isn't the case as we'll see. 114 00:07:52,220 --> 00:07:54,040 Once you've seen how we're going to write the code for this app, 115 00:07:54,260 --> 00:07:58,910 read through the documentation and it should all make more sense than trying to work from the documents 116 00:07:58,910 --> 00:08:00,330 alone. 117 00:08:00,390 --> 00:08:02,930 OK so the final parameter to requestPermissions 118 00:08:02,950 --> 00:08:07,850 is a result code and I've used a constant that I created earlier. Go back to our code, 119 00:08:07,850 --> 00:08:08,880 this one here. 120 00:08:09,420 --> 00:08:14,150 So the reason for that constant is because when you call the requestPermissions method you don't get 121 00:08:14,150 --> 00:08:14,730 the result 122 00:08:14,730 --> 00:08:21,080 back straight away. The system pops up a dialog, or the dialog, that we saw in the slides earlier, to ask 123 00:08:21,080 --> 00:08:22,970 the user to grant the permissions. 124 00:08:23,190 --> 00:08:29,190 Now if our onCreate method waited for the user to either grant or deny the request, 125 00:08:29,250 --> 00:08:34,590 then our app would be blocking and that's almost always never a good idea with an Android application. 126 00:08:34,679 --> 00:08:38,929 Now we discussed that when we were looking at async tasks in the top 10 Downloader and Flickrbrowser 127 00:08:38,929 --> 00:08:44,090 apps. It's not a good idea for our apps to block the UI thread and prevent the users from answering their 128 00:08:44,090 --> 00:08:45,180 phones. 129 00:08:45,250 --> 00:08:51,110 So instead, the Android framework displays the dialog and the requestPermissions method returns immediately. 130 00:08:51,770 --> 00:08:54,540 To find out whether the permission was granted or denied, 131 00:08:54,680 --> 00:09:00,890 what we have to do is implement a callback method that will be called once the user has made the decision. 132 00:09:00,920 --> 00:09:02,350 So let's actually write that, 133 00:09:02,420 --> 00:09:05,200 and we'll put this straight after the onCreate method. 134 00:09:05,400 --> 00:09:06,340 So I'm going to come down here, 135 00:09:07,240 --> 00:09:11,500 and start it immediately below the onCreate method as I said. 136 00:09:11,500 --> 00:09:13,810 Now we can get Android Studio to generate the stub for us, so 137 00:09:13,810 --> 00:09:20,870 I'm going to do a control o here, then we'll do a search for onRequest - I'm just typing onRequestPermissionsResults. 138 00:09:21,010 --> 00:09:27,380 As soon as we find the one we want, press enter there, and add the stub. I'm going to type this code in and 139 00:09:27,550 --> 00:09:28,080 then talk about it. 140 00:09:28,080 --> 00:09:31,750 For now I'm going to delete that first line, that super call, and I'm going to add a log there, 141 00:09:31,840 --> 00:09:38,560 log entry, Log.d parentheses TAG comma double quotes onRequestPermissionsResult 142 00:09:41,150 --> 00:09:53,550 colon starts. Then we're going to do when parentheses requestCode code block. We're going to do REQUEST_CODE_READ 143 00:09:53,560 --> 00:09:56,540 underscore CONTACTS dash greater than sign, 144 00:09:56,760 --> 00:09:59,080 then a left and right curly brace. 145 00:09:59,370 --> 00:10:09,180 Then within there we're going to put readGranted equals if parentheses grantResults 146 00:10:09,720 --> 00:10:21,180 dot isNotEmpty, and grantResults, left and right square braces and then zero, so index 0 is equal to 147 00:10:21,750 --> 00:10:23,600 PackagerManager dot. 148 00:10:23,850 --> 00:10:26,950 PERMISSION_GRANTED, then right parentheses. 149 00:10:26,990 --> 00:10:28,520 Then open a code block there. 150 00:10:28,970 --> 00:10:36,440 So at this point, in terms of our code, we can note here that permission was granted but the error will go away 151 00:10:36,450 --> 00:10:39,700 shortly, so "permission was granted, 152 00:10:41,440 --> 00:10:50,570 Yay" and then "Do the contacts-related task we need to do." 153 00:10:51,860 --> 00:10:53,820 So we're just going to return true there. 154 00:10:54,360 --> 00:10:56,010 Otherwise we'll run else 155 00:10:56,570 --> 00:10:59,550 then the code block again; 156 00:10:59,580 --> 00:11:00,300 "permission denied", 157 00:11:00,350 --> 00:11:04,400 at this point we get to this part of the code, denied, "boo!!" 158 00:11:05,080 --> 00:11:14,660 So we want to "Disable the functionality that depends on this permission". 159 00:11:15,360 --> 00:11:16,950 and we'll just add a log entry there; 160 00:11:17,210 --> 00:11:22,930 Log.d parentheses onRequest, or sorry TAG comma double quotes onRequest 161 00:11:25,470 --> 00:11:34,030 Permission, PermissionsResult colon permission refused. 162 00:11:34,670 --> 00:11:37,820 OK, and what I should probably do there, I put a typo there, 163 00:11:38,760 --> 00:11:46,380 let's also put a log entry there above the true, so we can see whether the permissions were successful 164 00:11:46,380 --> 00:11:46,820 or not. 165 00:11:46,920 --> 00:11:53,610 So we'll put permission granted for that one, and here we're going to return false, so false. 166 00:11:53,670 --> 00:11:56,820 Then right down the bottom here, just before the end of the function, 167 00:11:56,830 --> 00:12:08,040 we're going to put Log.d parentheses TAG comma double quotes onRequestPermissionsResult. PermissionsResult colon 168 00:12:08,130 --> 00:12:14,400 ends. Now I've lifted this code almost verbatim from a Google training document. 169 00:12:14,420 --> 00:12:15,780 I just want to quickly bring that up on the screen, 170 00:12:22,300 --> 00:12:27,830 and if we scroll down, the section that we're looking for is Handle the permission, the permissions request 171 00:12:27,830 --> 00:12:35,730 response, this part of the code, this is the code here. Now you can see the code is very similar to what's showing in there; it's 172 00:12:35,740 --> 00:12:37,510 almost verbatim. 173 00:12:37,510 --> 00:12:42,060 Now we're going to be adding a bit more to it later, to deal with the permission being denied, 174 00:12:42,190 --> 00:12:45,070 but this will do for now just to get an idea of what's happening. 175 00:12:45,070 --> 00:12:51,010 Basically when Android calls this method for us, it'll pass in the response code that we provided when 176 00:12:51,010 --> 00:12:55,900 we called the requestPermissions method. And going back to our code, 177 00:12:55,970 --> 00:13:02,920 that's what the constant REQUEST_CODE_READ_CONTACTS is for. Now in a larger 178 00:13:02,930 --> 00:13:07,940 app, we may well be requesting several permissions; an app that records video, for example, would need to 179 00:13:07,940 --> 00:13:09,250 get access to the camera, 180 00:13:09,350 --> 00:13:14,990 the microphone and also the storage, so that it can save the video. By providing a unique response 181 00:13:14,990 --> 00:13:17,610 code when calling requestPermissions, 182 00:13:17,690 --> 00:13:21,940 we can tell which particular request we're getting the results back for. Now here 183 00:13:21,980 --> 00:13:23,480 there's only one request, 184 00:13:23,590 --> 00:13:27,420 and we don't need to switch statement to check which one the results apply to, 185 00:13:27,620 --> 00:13:32,310 but it is useful to see how to handle multiple requests from a single activity. 186 00:13:32,660 --> 00:13:34,470 Alright, so that's the request code, 187 00:13:34,490 --> 00:13:37,900 the first parameter. The next one is permissions - 188 00:13:38,020 --> 00:13:41,300 well, actually the next two arguments are both arrays. We've got permissions 189 00:13:41,360 --> 00:13:47,660 and we've also got grantResults as you can see. The first contains the permissions we have requested and the second 190 00:13:47,660 --> 00:13:50,210 contains the result for each permission. 191 00:13:50,270 --> 00:13:56,020 It's possible that the user could grant some permissions and deny others, if we'd requested several at once, 192 00:13:56,030 --> 00:14:00,320 so this allows us to check which ones were accepted and which were denied. 193 00:14:00,320 --> 00:14:05,810 Now again we've only requested a single permission - READ_CONTACTS - so we're only interested in 194 00:14:05,810 --> 00:14:08,110 the first item in the grantResults array, 195 00:14:08,360 --> 00:14:14,180 and you can see the code now for that on line 69. If that permission's granted, then we can set the Boolean 196 00:14:14,180 --> 00:14:15,960 field readGranted to true, 197 00:14:16,160 --> 00:14:19,970 so we know we do have the permission. We'll look at things we can do if 198 00:14:19,970 --> 00:14:21,730 a permission is denied, a bit later. 199 00:14:21,970 --> 00:14:28,070 For now though if the permission is denied, then readGranted will be false, and once again, we really shouldn't 200 00:14:28,070 --> 00:14:28,900 be doing that. 201 00:14:29,120 --> 00:14:35,600 As I mentioned, it may be an obvious thing to try to do. When you do it and get in a mess it's not immediately 202 00:14:35,600 --> 00:14:37,730 obvious what's causing the mess. 203 00:14:37,730 --> 00:14:42,150 And if you've done any web development work then you'll know exactly where I'm going with this. 204 00:14:42,200 --> 00:14:44,250 Don't try and save state. 205 00:14:44,300 --> 00:14:46,930 If that doesn't mean much to you don't worry - it'll soon become clear. 206 00:14:47,150 --> 00:14:51,440 So that should work and we've got some logging code now that'll let us see what's going on. 207 00:14:51,530 --> 00:14:56,690 I'll stop the video here, and in the next one we'll run the app and see what happens when the user accepts 208 00:14:56,690 --> 00:14:58,410 and denies the permission. 209 00:14:58,430 --> 00:14:59,360 So you in the next video.