1
00:00:04,870 --> 00:00:10,130
Alright, so for the last video in this section, we're going to look at what happens when we get an error, and

2
00:00:10,130 --> 00:00:12,590
the user resolves the cause of that error.

3
00:00:12,590 --> 00:00:18,540
Now we've seen how to check isUserRecoverableError error, and show the error dialogue if they can recover,

4
00:00:18,730 --> 00:00:24,160
but what we haven't done, is look at how our app can respond if the user does fix the error.

5
00:00:24,410 --> 00:00:27,750
So let's start by reminding ourselves of what happens on the device.

6
00:00:28,130 --> 00:00:32,900
So I've got my Nexus 5 emulator loaded, running Android Oreo API 26.

7
00:00:32,980 --> 00:00:37,620
Now, we'll just swing back over to that, and you can see that it's set up as from the last video.

8
00:00:37,780 --> 00:00:43,080
Now I can't uninstall YouTube from the emulator, but what I can do is disable it. So

9
00:00:43,330 --> 00:00:45,280
what I'm going to do is close down the app, and

10
00:00:45,500 --> 00:00:48,100
I'm going to go into settings and then Apps and notifications,

11
00:00:51,080 --> 00:00:54,530
go into settings, then Apps and notifications down here.

12
00:00:55,070 --> 00:00:56,760
That's the new name for it by the way,

13
00:00:56,920 --> 00:01:02,160
and now from there, tap in App info, takes me to list of the apps that are installed on this, this

14
00:01:02,260 --> 00:01:03,590
device, this emulator,

15
00:01:03,890 --> 00:01:07,950
and YouTube's going to be right down the bottom, because it's in alphabetical order. So there's the YouTube Player, so

16
00:01:08,170 --> 00:01:12,230
we're going to click on that. Well actually I'm not going to click on that YouTube Player because that's

17
00:01:12,230 --> 00:01:16,100
actually our app. We're going to click on the one directly above it, which is the YouTube App that we're

18
00:01:16,110 --> 00:01:23,450
trying to disable. You can see there's now an option for this to disable the YouTube App, so click on Disable,

19
00:01:23,810 --> 00:01:28,920
and again its telling us what will happen but we're OK with that, so click on Disable App. Alright, now click on the back

20
00:01:28,920 --> 00:01:33,580
button to eventually get back to the main screen again, then I can just close this down.

21
00:01:34,230 --> 00:01:39,780
So let's now run the app and see what happens. I'm going to click on that again to start it, and

22
00:01:39,930 --> 00:01:47,040
swing over to the emulator. OK I'm going to play a single video, and you can see now we're getting a different message,

23
00:01:47,060 --> 00:01:53,630
and that's because YouTube's disabled, and you can see here that the users give it a chance to fix the problem,

24
00:01:53,700 --> 00:01:56,770
in this case by enabling YouTube on their device.

25
00:01:57,150 --> 00:02:04,900
So I'm going to tap that, Enable YouTube App. Once I do that, we get taken into the settings for the YouTube App.

26
00:02:05,080 --> 00:02:09,340
OK I'm going to click on enable, then I'm going to click on back, and you can see what's happened here.

27
00:02:09,340 --> 00:02:13,870
Even though the YouTube App is now enabled, and the user in fact fixed the problem, but

28
00:02:13,870 --> 00:02:18,470
our app's are not responding to the fix. So we can get around that by going back, and clicking on Play

29
00:02:18,470 --> 00:02:24,400
a single video. It then works, and obviously that time the video starts playing.

30
00:02:24,790 --> 00:02:29,680
So, that's pretty impressive but it isn't the greatest user experience.

31
00:02:29,800 --> 00:02:34,900
Now what they'll probably expect, is once they'd fixed the problem, in other words once they'd enabled YouTube, the video

32
00:02:34,900 --> 00:02:40,270
should start playing straight away without them having to go back and sort of restart or replay the video.

33
00:02:40,620 --> 00:02:44,620
And in our purpose as App Developers, we live to keep our users happy.

34
00:02:44,620 --> 00:02:46,630
So what can we actually do about this?

35
00:02:46,960 --> 00:02:52,120
Well remember that request code that we passed to the getErrorDialog method in the YoutubeActivity class? Let's just

36
00:02:52,120 --> 00:02:53,220
go back and have a look at that.

37
00:02:55,380 --> 00:03:01,900
Go back to our YouTubeActivity class, and this request code that I'm talking about here on line 57, and

38
00:03:01,900 --> 00:03:09,050
we're then passing that as you can see on line 60, to the youTubeInitializationResult.getErrorDialog.

39
00:03:09,060 --> 00:03:13,660
Now the documentation for the getErrorDialog function that we looked at, mentioned something about the

40
00:03:13,660 --> 00:03:16,090
second parameter, so let's just go and bring that up briefly.

41
00:03:20,830 --> 00:03:25,810
And you can see here, talking about the Parameters requestCode, "The requestCode given when calling start

42
00:03:25,810 --> 00:03:30,370
ActivityForResult". It doesn't actually give us any more information than that.

43
00:03:30,370 --> 00:03:35,540
Now, so we've used startActivity to launch our other two activities for MainActivity when the buttons were tapped. Start

44
00:03:35,560 --> 00:03:42,310
ActivityForResult is similar, but it also allows a result to be passed back to the starting activity.

45
00:03:42,310 --> 00:03:46,880
So with a bit of guesswork, remembering that the source for the YouTube library isn't available,

46
00:03:46,930 --> 00:03:51,340
we can try to retrieve the result, but as it happens we'll actually fail.

47
00:03:51,820 --> 00:03:55,230
And that's why we don't cover this in the Java version of this course,

48
00:03:55,360 --> 00:03:58,920
but enough students have asked, and we've included it here in the Kotlin version,

49
00:03:59,100 --> 00:04:04,920
and we'll hopefully find time to address this, to add this video in the Java Android version of the course.

50
00:04:05,020 --> 00:04:09,930
So what we're going to do is, we're going to fail to get a useful response back from the dialogue,

51
00:04:10,120 --> 00:04:13,270
but what we do get turns out to be good enough.

52
00:04:13,270 --> 00:04:17,300
So let's start by having a look at what startActivity is all about.

53
00:04:17,860 --> 00:04:25,600
So we do a search in Google for it, so Google, and we're going to do a search for startActivityForResult.

54
00:04:30,680 --> 00:04:34,770
And you can see we've got this result here, 'Getting a Result from an Activity', in the Google documentation.

55
00:04:38,200 --> 00:04:45,120
So basically we can start another activity, and receive a callback, if we use startActivityForResult instead

56
00:04:45,120 --> 00:04:46,420
of startActivity.

57
00:04:46,830 --> 00:04:51,360
Now there's a section if you scroll down and read this, on how to receive the results, a bit further in

58
00:04:51,360 --> 00:04:57,810
this document, and we'll get the result when the other activity calls our onActivityResult method, and

59
00:04:57,810 --> 00:05:01,350
passes it the original request code and also our result code.

60
00:05:01,530 --> 00:05:04,760
And further, the document also talks about a resultCode of RESULT_

61
00:05:04,770 --> 00:05:09,700
OK, and you can see this here, if resultCode equals RESULT_OK  as an example there. And

62
00:05:09,970 --> 00:05:12,930
we can check that, and again a bit more Googling, and

63
00:05:12,940 --> 00:05:17,540
by following the reference links in our last search, we'll eventually get to another website, which

64
00:05:17,580 --> 00:05:23,450
I'm just going to paste in here now to save a bit of time, and we'll eventually get to here,

65
00:05:24,800 --> 00:05:26,360
and you can see we've got RESULT_

66
00:05:26,390 --> 00:05:32,280
OK is minus one, constant value down here, and RESULT_CANCELLED is zero.

67
00:05:32,300 --> 00:05:34,850
So we can use that and put that to good effect.

68
00:05:34,850 --> 00:05:38,250
Now this next bit that I'm going to show you is a sort of a leap of faith,

69
00:05:38,420 --> 00:05:42,680
after all we haven't actually called any variant of startActivity, as far as we know.

70
00:05:42,680 --> 00:05:49,440
We've just used the getErrorDialog in our code to request that dialogue. You can see the code there on line 60.

71
00:05:49,700 --> 00:05:54,170
But what we don't know when the YouTube classes or what they're actually doing behind the scenes.

72
00:05:54,330 --> 00:05:59,720
Now we do provide a reference to our YoutubeActivity when we pass this to getErrorDialog, and you can see

73
00:05:59,720 --> 00:06:01,230
that again on line 60.

74
00:06:01,460 --> 00:06:06,890
So that method's quite capable of using a dialogue fragment, or even another activity on our behalf,

75
00:06:07,250 --> 00:06:13,130
to display the error dialog. Now the YouTube documentation mentions startActivityForResult.

76
00:06:13,340 --> 00:06:19,550
So all we can really do here is create an onActivityResult function, and see if it gets called.

77
00:06:19,550 --> 00:06:23,750
This is the leap of faith that we're talking about. Now all this may give you some idea why we didn't include

78
00:06:23,750 --> 00:06:27,590
this in the previous version of the course. It does get slightly worst,

79
00:06:27,650 --> 00:06:29,930
but let's go and give it a go and see what happens anyway.

80
00:06:30,430 --> 00:06:36,420
So I'm to going to come down here to the end of YoutubeActivity, and I'm going to put this function

81
00:06:36,420 --> 00:06:38,370
right down the bottom. I'm going to override that, so we've got this

82
00:06:41,120 --> 00:06:44,100
onActivityResult as you can see there, so I'm going to select that one.

83
00:06:44,490 --> 00:06:46,030
So let's actually add some code for it.

84
00:06:46,030 --> 00:06:48,770
Now we don't want the super call, so let's get rid of that.

85
00:06:48,770 --> 00:06:56,910
So we'll start with some logging, so Log.d parentheses tag comma, we'll call it onActivityResult, because obviously 

86
00:06:56,990 --> 00:07:05,130
we want to see this being logged, that it's been called, called, then, with request code, dollar request code, and

87
00:07:07,920 --> 00:07:11,930
for result code, actually what we'll do just to make it more sensible here,

88
00:07:11,940 --> 00:07:28,310
we'll actually change this. We'll start with response code, resultCode, we'll close that down,

89
00:07:32,310 --> 00:07:36,580
so obviously Kotlin's getting a bit confused by what I'm typing here but the code will still work.

90
00:07:36,790 --> 00:07:43,480
So call the response code, resultCode for request dollar requestCode.

91
00:07:43,740 --> 00:07:55,860
OK, so on the next line if parenthesis requestCode, that's equal to DIALOG capitals underscore REQUEST

92
00:07:56,530 --> 00:08:06,520
underscore CODE, open a code block, Log.d TAG intent question mark 

93
00:08:06,590 --> 00:08:15,520
dot toString, then a Log.d parentheses TAG intent question mark again, dot

94
00:08:15,590 --> 00:08:21,580
extras dot toString, and we've got an error there but we'll fix that in a moment.

95
00:08:21,590 --> 00:08:27,800
Now when you use startActivityForResult, you provide a requestCode. When the started activity

96
00:08:27,800 --> 00:08:31,000
calls your onActivityResult, it sends back that requestCode.

97
00:08:31,000 --> 00:08:35,960
So that's just requestCode here that we've got here in the log on line 112, that's actually showing

98
00:08:35,960 --> 00:08:38,549
us a parameter for the onActivityResult.

99
00:08:38,750 --> 00:08:43,549
And that's because you may be starting more than one activity, and you need to know which result goes

100
00:08:43,549 --> 00:08:44,470
with which one.

101
00:08:44,660 --> 00:08:50,790
And that's why I've used the DIALOG_REQUEST_CODE constant, and why we check it here,

102
00:08:51,110 --> 00:08:55,090
so better to clear that to get rid of that error. So let's go back up to the top of the class and do

103
00:08:55,090 --> 00:09:01,090
that. We'll put them immediately below the YoutubeActivity TAG, so private

104
00:09:02,060 --> 00:09:11,870
val DIALOG_REQUEST_CODE equals one, and obviously by doing that we'll fix the error that we had in our code.

105
00:09:11,870 --> 00:09:15,490
Now we're going to use that constant when calling the getErrorDialog method.

106
00:09:15,650 --> 00:09:19,680
So let's go back and do that. That's in the onInitializationFailure. Alright up here, so at the moment 

107
00:09:20,890 --> 00:09:28,190
we've got getErrorDialog and we've got two arguments. We've got 'this' and we've got this request code.

108
00:09:28,320 --> 00:09:32,970
We're going to change this request code now to DIALOG_REQUEST_CODE, our constant we've just defined, like so,

109
00:09:36,170 --> 00:09:43,710
and now that we're not using the request code val here, so we'll get rid of that. Alright so back to our onActivity

110
00:09:43,710 --> 00:09:46,570
Result function, let's go back down to the bottom again.

111
00:09:46,620 --> 00:09:49,880
Now all we're doing at the moment, is logging the values that we get back.

112
00:09:50,100 --> 00:09:55,040
So we'd log the resultCode and requestCode and also the contents of the intent.

113
00:09:55,260 --> 00:09:59,740
So let's actually see what we do get back. So we're going to go back to our app, so

114
00:09:59,970 --> 00:10:03,420
firstly what I'm going to do is disable our YouTube again, the YouTube App.

115
00:10:03,800 --> 00:10:09,370
So I'm going to go back into Apps and notifications, App info, scroll

116
00:10:09,660 --> 00:10:14,070
right down to the bottom. There's our YoutTube App,

117
00:10:14,110 --> 00:10:17,010
we're going to disable that, Disable app,

118
00:10:18,010 --> 00:10:26,270
close this down. Alright, and we should get the same error we got last time. I click on Play a single video.

119
00:10:26,470 --> 00:10:32,430
The app, we got the same error that we got last time about enabling YouTube. Now if we've guessed correctly

120
00:10:32,430 --> 00:10:35,720
at this point, based on the hints in the documentation,

121
00:10:35,910 --> 00:10:41,530
we should get our onActivityResult function called, with a result of minus one,

122
00:10:41,610 --> 00:10:47,940
when we re-enable the YouTube App. So I'm going to open the Logcat first, then what I'm going to do,

123
00:10:48,230 --> 00:10:54,750
I'm going to filter the Logcat on YoutubeActivity, YoutubeActivity.

124
00:10:56,020 --> 00:11:03,350
So let's go back and click on Enable YouTube App, click on enable, then we're going to click on back, and we can see we've

125
00:11:03,350 --> 00:11:05,780
got something here now, back in our log.

126
00:11:06,520 --> 00:11:08,360
And you can see we've got request code, I'll put,

127
00:11:08,640 --> 00:11:13,550
I should've actually put request code there but you can see that we've got one returned there, and the response code

128
00:11:13,550 --> 00:11:14,700
returned was zero.

129
00:11:14,860 --> 00:11:19,910
So one was for the request code which is in line with the DIALOG_REQUEST_CODE, and the result we got

130
00:11:19,910 --> 00:11:21,060
back was zero.

131
00:11:21,440 --> 00:11:26,560
So, there's basically a problem there. We were expecting minus 1 for the resultCode but we got the resultCode

132
00:11:26,570 --> 00:11:31,450
of zero, which wasn't expected. So that implies that the user cancelled.

133
00:11:31,490 --> 00:11:34,400
Now I won't do this, but by all means do it yourself.

134
00:11:34,420 --> 00:11:40,520
but if we ran through that test again, and didn't enable YouTube, we'd still get zero return.

135
00:11:40,520 --> 00:11:46,250
So it seems that the getErrorDialog can't detect what the user did, once they've been taken into the settings,

136
00:11:46,250 --> 00:11:48,720
so just returns zero, in other words, regardless.

137
00:11:48,920 --> 00:11:53,880
So if we can't tell if the user's enabled YouTube, what actually can we do next?

138
00:11:54,800 --> 00:11:56,630
Well, what are our options in other words.

139
00:11:56,920 --> 00:12:02,510
Well if they did enable YouTube, we'd initialize our player again, but if they didn't enable YouTube,

140
00:12:02,840 --> 00:12:05,120
is there any harm in initializing the player again?

141
00:12:05,240 --> 00:12:08,290
What's the worst that can happen. We just end up right back here.

142
00:12:08,900 --> 00:12:10,750
So let's actually see how that works out.

143
00:12:10,910 --> 00:12:15,540
What we're going to do is we're going to ignore the response code and initialize the player again if the

144
00:12:15,550 --> 00:12:20,240
user did go into the settings, and our onActivityResult function gets called.

145
00:12:20,240 --> 00:12:25,310
So basically all we want to do is leave the logging there, and on the line after the two logs we're

146
00:12:25,310 --> 00:12:32,200
going to put playerView, and we get an error there which we'll talk about shortly, so playerView.initialize

147
00:12:33,640 --> 00:12:44,620
parentheses, getString parentheses R.string.GOOGLE_API_KEY parentheses comma this, then closing

148
00:12:44,620 --> 00:12:46,110
parentheses.

149
00:12:46,120 --> 00:12:50,400
Now we're getting that error because playerView's currently local to the onCreate method,

150
00:12:50,590 --> 00:12:55,650
so in other words we need to make the playerView available throughout the activity. So we come back up

151
00:12:55,660 --> 00:12:59,910
to the onCreate method, there's our playerView.

152
00:13:00,710 --> 00:13:07,880
So let's move that declaration. Move it out of there and I'm going to put it up here, just below our constant

153
00:13:07,880 --> 00:13:11,340
that we defined up here, the val for the DIALOG_REQUEST_CODE.

154
00:13:14,000 --> 00:13:20,700
Now what we need to do is make a little bit of a change to that, so val playerView equals, so we'll change that to

155
00:13:20,700 --> 00:13:27,070
by lazy, which we talked about before, then add a CODE block around that code.

156
00:13:27,390 --> 00:13:33,420
So, we have to use a lazy initialization which we've done here, because you can't instantiate a YouTube playerView

157
00:13:33,420 --> 00:13:38,340
until after we add it to the layout in onCreate, in case you're wondering why I've done it that way.

158
00:13:38,520 --> 00:13:44,070
Alright so with that done now, we should find that if the log had got an error, in our onActivityResult as you

159
00:13:44,070 --> 00:13:49,290
can see, so how does it behave at this point. Let's go back to our emulator first.

160
00:13:49,440 --> 00:13:53,700
Actually I'll close the app down, so I think I've re-enabled it, so I'll just get back in and make sure that

161
00:13:53,700 --> 00:14:03,510
it is disabled. Click on YouTube, disable that. OK we'll get out of that, then we'll run our app again,

162
00:14:06,620 --> 00:14:15,070
Play a single video, enable YouTube app, then we'll go back and I'll attempt to initialize a player again. This just

163
00:14:15,070 --> 00:14:21,100
resultS in the same thing. we're getting an error dialog appearing again, with the option to enable the app.

164
00:14:21,210 --> 00:14:25,630
Now if the user really doesn't want to enable YouTube, they'll have to dismiss the dialogue with the

165
00:14:25,630 --> 00:14:28,180
back button or by tapping the screen outside the dialogue.

166
00:14:28,330 --> 00:14:36,640
But what happens if we do enable YouTube? Click on enable, click on Enable the YouTube button again, and go back.

167
00:14:37,480 --> 00:14:41,530
This time you can see it now has enabled it and the video's started playing.

168
00:14:41,530 --> 00:14:43,660
So that's a definite improvement.

169
00:14:43,660 --> 00:14:48,350
Now the app will crash if we try to play anything from a StandaloneActivity, when YouTube's disabled

170
00:14:48,350 --> 00:14:52,780
of course. If you want to catch the 'activity not found' exception in there to prevent a crash,

171
00:14:52,840 --> 00:14:54,870
that would make a good exercise for you to try, but

172
00:14:55,070 --> 00:14:58,240
I'm not going to go through a solution for that. It's basic exception handling,

173
00:14:58,480 --> 00:15:00,910
and we've been doing a fair bit of that throughout the course.

174
00:15:00,920 --> 00:15:05,650
Alright, so that's the end of this section. In the next section we're going to create an app to download and view photos

175
00:15:06,010 --> 00:15:10,250
from Flickr, which is an image sharing site. So I'll see you in the next video.

