1 00:00:05,190 --> 00:00:10,040 In the previous video, we got the app running on Android versions earlier than Marshmallow, which is API 2 00:00:10,050 --> 00:00:12,480 23. With API 23, 3 00:00:12,570 --> 00:00:17,850 Google changed the way that permissions work, and we looked at that briefly in the top 10 Downloader app. 4 00:00:18,690 --> 00:00:25,350 So I'm going to run the app again, but this time I've loaded the API 27 emulator that I set up in an earlier video in this 5 00:00:25,410 --> 00:00:29,610 section of the course, the one that we've also entered some contact details into. 6 00:00:30,270 --> 00:00:31,590 So this time when I run the app, 7 00:00:41,500 --> 00:00:47,840 so the app starts as per normal, but when I click on the floating action button we actually get an error 8 00:00:47,840 --> 00:00:48,130 here: 9 00:00:48,150 --> 00:00:52,190 Content Provider Example has stopped. And if we come and have a look at our logcat, we can 10 00:00:55,050 --> 00:01:02,100 see that we've got an exception. I'll just go back up and look at it. Now we can see it here, the error, Permission Denial. 11 00:01:02,820 --> 00:01:07,600 Basically it goes on to say the Permission Denial was for opening provider com.android.providers 12 00:01:07,620 --> 00:01:11,170 dot contacts.ContactsProvider2. 13 00:01:11,370 --> 00:01:17,430 The bottom line here is with API 23 and above, it's not enough to just request the permissions we need 14 00:01:17,430 --> 00:01:18,650 in the manifest. 15 00:01:18,690 --> 00:01:25,180 We also need to write some code to request the permissions from the user when the app runs. 16 00:01:25,220 --> 00:01:34,620 So let's check the Google documentation here. So there's a guide which is pretty useful about Permissions, Android 17 00:01:34,630 --> 00:01:36,690 Permissions. I'm just going to paste in the link there. 18 00:01:40,880 --> 00:01:47,170 Now as it turns out, this documentation has been updated since we looked at the top 10 app, and the earlier link now 19 00:01:47,230 --> 00:01:52,360 redirects to here. So I'm going to start with this Permissions Overview at the top of the page. But do have 20 00:01:52,360 --> 00:01:53,260 a read through this guide 21 00:01:53,260 --> 00:01:57,310 once you've finished this section, to make sure you understand how everything works. 22 00:01:57,490 --> 00:02:02,140 We already know that we have to specify the permission in the manifest, regardless of the version of 23 00:02:02,250 --> 00:02:02,670 Android. 24 00:02:02,830 --> 00:02:04,070 And we've already done that step 25 00:02:04,270 --> 00:02:08,070 when we added the user's Permission tag in the Android manifest.xml file. 26 00:02:08,320 --> 00:02:13,540 But another important thing to note is that, in that first paragraph, is that the system might grant 27 00:02:13,540 --> 00:02:19,110 the permission automatically. 28 00:02:19,220 --> 00:02:24,650 So that's what happened in our top 10 app, because the Internet permission we needed is classed as a normal 29 00:02:24,650 --> 00:02:25,720 permission. 30 00:02:25,730 --> 00:02:30,040 So what that means is we didn't have to do anything else to be granted permission to access the Internet. 31 00:02:30,350 --> 00:02:34,360 But accessing the user's contacts is classed as a dangerous permission, 32 00:02:34,550 --> 00:02:38,070 though, so Android needs to ask the user to approve that permission. 33 00:02:38,120 --> 00:02:41,800 Now we didn't really see that when we ran our app on the Lollipop emulator. 34 00:02:42,050 --> 00:02:47,840 That's because the method that Android Studio uses to install apps on the device, bypasses the checks 35 00:02:47,840 --> 00:02:51,320 that you see when you install an app from the Google Play Store. 36 00:02:51,350 --> 00:02:56,420 Now earlier in the course, we enabled USB debugging on our phones, and you should have seen a dialogue 37 00:02:56,450 --> 00:03:00,270 pop up asking for confirmation that looks something like this: 38 00:03:00,470 --> 00:03:06,800 Now notice that it does say that enabling USB debugging can install apps on your device without notification. 39 00:03:07,070 --> 00:03:12,770 The emulators have USB debugging turned on by default, and that automatically accepts the permissions 40 00:03:12,770 --> 00:03:16,300 that you'd normally have to accept when installing a new app. 41 00:03:16,310 --> 00:03:21,080 So although we didn't see it when running our apps from Android Studio, you'd normally have to accept 42 00:03:21,080 --> 00:03:24,750 the permission that the app requested when you install it. 43 00:03:25,340 --> 00:03:27,380 And that's how it worked before Marshmallow. 44 00:03:27,560 --> 00:03:32,460 But when Google released Marshmallow they changed the way that permissions work. 45 00:03:32,540 --> 00:03:37,650 So let's go back to that web page now, just to see what this all means for Marshmallow and above. 46 00:03:37,850 --> 00:03:42,110 So we can get a good description of the change by scrolling down to the Requests prompts for dangerous 47 00:03:42,110 --> 00:03:43,090 permissions section, 48 00:03:43,100 --> 00:03:44,950 to this section here. 49 00:03:45,620 --> 00:03:51,080 So that confirms what we found in the top 10 app: Only dangerous permissions require user agreement. 50 00:03:51,080 --> 00:03:55,900 Now the next subsection there describes the differences from the user's perspective. 51 00:03:58,330 --> 00:04:04,300 If the device is running Android 6.0 API Level 23 or higher, users grant permission to apps while the 52 00:04:04,300 --> 00:04:05,110 app is running, 53 00:04:05,260 --> 00:04:06,970 not when they install the app. 54 00:04:07,180 --> 00:04:11,920 There's also an important comment there about the target SDK version. 55 00:04:11,980 --> 00:04:16,050 The target SDK version has to be 23 or higher for this behavior. 56 00:04:16,209 --> 00:04:21,670 If you target a lower version, then your app will have the earlier behavior regardless of the device that 57 00:04:21,670 --> 00:04:22,530 it's running on. 58 00:04:22,630 --> 00:04:25,980 The user will be prompted to grant access when they install the app. 59 00:04:26,260 --> 00:04:31,750 It also states that you can't always rely on having a permission. The user may grant it, but then deny 60 00:04:31,750 --> 00:04:32,710 it again later. 61 00:04:33,010 --> 00:04:37,960 And if you think about it that obviously has implications for us as developers, because we now have to 62 00:04:37,960 --> 00:04:43,000 write our apps so that they can handle the situation where a permission is no longer granted. 63 00:04:43,150 --> 00:04:48,670 Now for some apps that may involve us disabling some functionality. An example could be a photo 64 00:04:48,700 --> 00:04:54,360 processing app that allows the user to share the modified photo with their contacts. 65 00:04:54,550 --> 00:04:59,620 If the user revokes the apps permission to access their contacts, then the app would be unable to share 66 00:04:59,620 --> 00:05:00,420 the photo. 67 00:05:00,700 --> 00:05:05,260 So in that case we shouldn't even display that option at all. The app would still be able to perform its photo 68 00:05:05,260 --> 00:05:11,260 manipulation functions but would be unable to share the result. Now in the case of our simple contacts 69 00:05:11,260 --> 00:05:11,680 app, 70 00:05:11,860 --> 00:05:17,500 if the user doesn't grant access to the contacts database, then the entire app will become useless because 71 00:05:18,010 --> 00:05:19,120 that's all it does. 72 00:05:19,360 --> 00:05:26,840 So the next section, if we scroll down a little bit more, talks about Install, Install-time requests. And by the way I didn't scroll down, 73 00:05:26,890 --> 00:05:31,670 but that other information that I was talking about related to Android 6.0 and higher is on that page there - you 74 00:05:31,670 --> 00:05:36,250 can see it talks more about not relying on always having the permission. But scrolling down further now 75 00:05:36,260 --> 00:05:40,650 we're talking about the Install-time requests Android 5.1.1 and below. 76 00:05:40,940 --> 00:05:46,190 That's describing the behavior on earlier versions of Android, and that also applies if your target is 77 00:05:46,190 --> 00:05:51,480 SDK version is 22 or lower, regardless of the version of Android that the device is running. 78 00:05:51,620 --> 00:05:55,730 So in that case the permissions are requested when the app is installed. 79 00:05:55,730 --> 00:05:59,950 The user can either grant all permissions or decide not to install the app, 80 00:06:00,540 --> 00:06:01,560 and talks more about that as 81 00:06:01,570 --> 00:06:04,180 we scroll down. If the permissions are granted, 82 00:06:04,460 --> 00:06:09,840 the only way to deny any of those permissions is to uninstall the app. So going back up the page now, 83 00:06:12,990 --> 00:06:16,440 just down here to the end of the Permission approval section, 84 00:06:16,870 --> 00:06:21,280 there's a link there to the protection levels - this link here. Now that lists the normal and dangerous 85 00:06:21,280 --> 00:06:26,440 permissions, and lets you check if you need to do more than just add an entry in the manifest for a specific 86 00:06:26,440 --> 00:06:30,620 permission or permissions that your apps need. Click on that and have a look, 87 00:06:31,210 --> 00:06:32,080 but I'll leave that for now. 88 00:06:32,080 --> 00:06:33,310 We'll go back to Android 89 00:06:33,340 --> 00:06:39,490 Studio, and let's now look at the code we need to check for those permissions, and then we'll consider what 90 00:06:39,490 --> 00:06:41,370 to do if they're not granted. 91 00:06:41,530 --> 00:06:46,630 But what I'm going to do first is start by adding a constant and a variable that we'll be using shortly. 92 00:06:46,960 --> 00:06:54,070 So I'm going to do that. I'm going to close down the logcat window, go up to the top of the file. So lay our constant below our TAG, so it's going 93 00:06:54,070 --> 00:06:55,390 to be private 94 00:06:55,400 --> 00:06:58,420 const Val. We'll call this one REQUEST, in 95 00:06:58,530 --> 00:07:06,410 uppercase, underscore CODE underscore READ underscore CONTACTS, and we'll assign the value of 1 to that, equals 1. 96 00:07:06,470 --> 00:07:08,500 And we're using that variable shortly. 97 00:07:08,670 --> 00:07:13,670 I'll also explain what it's for when we come to using it, but also in the class itself 98 00:07:13,720 --> 00:07:16,030 let's add a variable, and we're going to call it 99 00:07:16,070 --> 00:07:19,920 readGranted. So it's going to be private, private var 100 00:07:19,950 --> 00:07:21,100 and it's going to be read 101 00:07:21,110 --> 00:07:23,920 Granted equals false. 102 00:07:24,260 --> 00:07:26,570 Same deal, I'll talk about that shortly, 103 00:07:26,700 --> 00:07:31,480 and obviously in the case of the constant on line 14, you saw that I made it a top level value using the 104 00:07:31,480 --> 00:07:33,530 private const modifiers. 105 00:07:33,560 --> 00:07:38,320 Alright, so the first step now is to check to see if the app has already been granted the permission 106 00:07:38,320 --> 00:07:39,260 it needs. 107 00:07:39,450 --> 00:07:44,650 And we can do that by calling the checkSelfPermission method. So I'm going to add the code and then say a 108 00:07:44,650 --> 00:07:46,290 couple of things about it. 109 00:07:46,360 --> 00:07:48,750 So I want to put that code just immediately below this 110 00:07:48,760 --> 00:07:51,550 setSupportActionBar call. 111 00:07:51,860 --> 00:07:55,840 And it's going to be val hasReadContactPermission, 112 00:07:58,690 --> 00:08:03,520 and we'll set that equal to ContextCompat 113 00:08:03,740 --> 00:08:07,090 dot, and it's going to be check 114 00:08:07,110 --> 00:08:15,170 SelfPermission. In parentheses it's going to be this comma, and it's going to be Manifest. At this point here 115 00:08:15,190 --> 00:08:22,900 it's important to choose the android.Manifest package, this one down here and not the java.util one. So Manifest dot 116 00:08:23,050 --> 00:08:24,530 permission 117 00:08:25,210 --> 00:08:32,440 dot READ_CONTACT. And what I'm going to do is just put that on the next line. Actually I won't, it reads 118 00:08:32,440 --> 00:08:32,789 alright. 119 00:08:32,799 --> 00:08:36,690 I just wanted to make sure there's enough space on the screen to see that, but we can see that. 120 00:08:36,740 --> 00:08:38,669 So we're checking to see whether we've got that permission and 121 00:08:38,679 --> 00:08:43,120 I'm just going to do a log entry here - Log.d parentheses TAG comma. 122 00:08:43,289 --> 00:08:48,060 Then in double quotes onCreate colon check 123 00:08:48,070 --> 00:08:48,600 SelfPermission 124 00:08:51,170 --> 00:08:55,660 returned $hasReadContactPermission. 125 00:08:56,760 --> 00:09:02,130 Now because the new security model was introduced in API 23 and we're targeting Android versions way 126 00:09:02,130 --> 00:09:08,580 back to API 17, we have to use the v4.support library to get access to the checkSelfPermission 127 00:09:08,580 --> 00:09:09,350 method. 128 00:09:09,360 --> 00:09:14,050 Now there is a checkSelfPermission method in the framework, but that would only work for Marshmallow 129 00:09:14,050 --> 00:09:14,980 and above. 130 00:09:15,060 --> 00:09:21,460 And both methods return the same result, but the ContextCompat method which we selected, first checks 131 00:09:21,460 --> 00:09:26,790 to see if it's running on Android prior to API 23. If it is it just a little success, 132 00:09:26,850 --> 00:09:31,170 and that's of course because the new security model doesn't apply before API 23. 133 00:09:31,170 --> 00:09:34,990 Now remember that we defined the permissions we needed in the manifest, 134 00:09:35,220 --> 00:09:40,320 so therefore we can use the constants defined in the manifest's class to specify which permission we're 135 00:09:40,320 --> 00:09:40,910 checking. 136 00:09:41,020 --> 00:09:46,350 Here it's the READ_CONTACTS permission. So having to type Manifest.permission.READ 137 00:09:46,350 --> 00:09:47,150 underscore CONTACTS 138 00:09:47,160 --> 00:09:49,010 everytime is a bit of a mouthful, 139 00:09:49,140 --> 00:09:54,810 so we can import the constant from android.Manifest.permission instead. Now Android Studio add the import 140 00:09:54,810 --> 00:09:55,570 for us, 141 00:09:55,740 --> 00:10:01,590 so first note that android.Manifest has been imported to give us access to the Manifest.permission 142 00:10:01,590 --> 00:10:03,750 dot READ_CONTACTS field. 143 00:10:03,840 --> 00:10:10,010 So if we have a look in the import section, you can see here, android.Manifest. In my case, it's literally 144 00:10:10,010 --> 00:10:15,670 the first entry of the import section of the source code. The ordering of course isn't important, 145 00:10:15,890 --> 00:10:19,030 so it may well be appearing lower down for you. 146 00:10:19,550 --> 00:10:23,940 So if I go back and remove the Manifest.permission qualifier from the READ_CONTACTS field - 147 00:10:24,100 --> 00:10:25,760 I'll just make that READ_CONTACTS, 148 00:10:28,900 --> 00:10:33,230 and what I can do is just delete that if needed. You can see the old one's still there but it has actually added 149 00:10:33,230 --> 00:10:33,680 the new ones. 150 00:10:33,680 --> 00:10:35,900 I'm just going to delete the old one. 151 00:10:37,150 --> 00:10:41,600 But what it should do then, as you can see, it added the android.Manifest.permission.READ 152 00:10:41,600 --> 00:10:42,980 underscore CONTACTS. 153 00:10:43,220 --> 00:10:47,130 So therefore we can now get away with just putting READ_CONTACTS here. 154 00:10:47,180 --> 00:10:53,250 Let me just take this opportunity to check my preferences here. I'm going into Preferences, going into Editor, 155 00:10:53,930 --> 00:10:59,540 General, Auto import, and I've got Add unambiguous imports on the fly and Optimize imports on the fly 156 00:10:59,600 --> 00:11:00,990 which is what that uses. 157 00:11:00,990 --> 00:11:02,270 So I'm not sure why that other 158 00:11:02,270 --> 00:11:07,070 grey entry appeared and appeared to sit there for a while but it should be automatic, and remove that 159 00:11:07,070 --> 00:11:07,910 automatically for me. 160 00:11:07,970 --> 00:11:09,900 But anyway, at this point we've actually succeeded now. 161 00:11:10,200 --> 00:11:15,440 We've got a the line making it a lot easier to read now, using just READ_CONTACTS rather than the qualifier 162 00:11:15,440 --> 00:11:17,360 that we had previously. 163 00:11:17,360 --> 00:11:20,970 So at this point though, looking at this import on line 3, 164 00:11:21,410 --> 00:11:24,520 that's the equivalent of what's called a static import in java. 165 00:11:24,890 --> 00:11:29,690 Now if you're not familiar with the static imports in Java, that's just a way to import the static members 166 00:11:29,690 --> 00:11:30,670 of a class, 167 00:11:30,680 --> 00:11:34,380 and these are usually constants and it saves having to fully qualify them. 168 00:11:34,500 --> 00:11:38,990 Kotlin doesn't have the static keyword, but importing the fully qualified value like 169 00:11:38,990 --> 00:11:45,410 this is the Kotlin equivalent. Importing like this can be useful, but use it sparingly. If you over 170 00:11:45,410 --> 00:11:45,730 do it 171 00:11:45,740 --> 00:11:49,110 you can make your code hard to understand and debug. 172 00:11:49,260 --> 00:11:52,950 Now to see what I mean, have a look at the code - coming down here again - 173 00:11:54,340 --> 00:12:01,770 from line 27 onwards. And if you look at that code from line 27 onwards, it's now not immediately obvious where READ 174 00:12:01,770 --> 00:12:07,730 underscore CONTACTS is coming from, and if it had also imported the ContactsContract constants, we'd have 175 00:12:07,730 --> 00:12:11,020 a lot of constants coming from different classes without being qualified. 176 00:12:11,240 --> 00:12:16,090 And that can make it hard to see what's going on and where all these constants are coming from. 177 00:12:16,100 --> 00:12:20,040 So I recommend not using this type of import for more than one class at a time. 178 00:12:20,060 --> 00:12:22,150 Alright so back to line 27. 179 00:12:22,190 --> 00:12:26,960 So we've passed a context, this here, as the first parameter, 180 00:12:27,350 --> 00:12:32,620 and we also passed a constant representing the permission we're interested in to the checkSelf 181 00:12:32,620 --> 00:12:33,740 Permission method. 182 00:12:33,760 --> 00:12:35,670 Now we'll get back an int result. 183 00:12:35,860 --> 00:12:39,500 So let's check the documentation to see what the return value is. 184 00:12:39,500 --> 00:12:42,890 So I'm going to click on the checkSelfPermission method and bring up the documentation, 185 00:12:47,490 --> 00:12:50,310 and you can see that these return values are fairly straightforward. 186 00:12:50,540 --> 00:12:55,970 We get one of the two constants returned; either PERMISSION_GRANTED if we already have the permission, 187 00:12:56,390 --> 00:12:58,030 or PERMISSION_DENIED 188 00:12:58,040 --> 00:13:04,300 if we don't. Now on Android versions before Marshmallow, we should always get PERMISSION_GRANTED as long as 189 00:13:04,310 --> 00:13:09,650 we specify the permission in the manifest. On Marshmallow and above, the permission won't have been 190 00:13:09,650 --> 00:13:11,420 granted when the app was installed, 191 00:13:11,540 --> 00:13:16,160 and that means that the first time we run this app, we'll get PERMISSION_DENIED and we'll 192 00:13:16,170 --> 00:13:18,710 have to request the permission from the user. 193 00:13:18,750 --> 00:13:22,760 This is where things get a bit interesting. Now it would be fairly straightforward except that 194 00:13:22,760 --> 00:13:27,730 users have an option to deny a permission, and you can tick a box so that they won't get asked again. 195 00:13:27,830 --> 00:13:31,370 I'm going to have a look at how that works and how to deal with it in the next video.