1
00:00:05,250 --> 00:00:11,770
Alright, so now that we've added the YouTubePlayerView widget to our layout, and we've got our Google API key set up and

2
00:00:11,770 --> 00:00:13,300
added to this project,

3
00:00:13,300 --> 00:00:17,770
it's time to write the code that'll actually go ahead and play the videos for us.

4
00:00:17,770 --> 00:00:23,020
Now the first thing we need to do is initialize the player, which is how we tell it what our key is, and we

5
00:00:23,020 --> 00:00:26,110
do that by calling the players initialize method.

6
00:00:26,110 --> 00:00:31,950
So we want to be in YoutubeActivity, and the code we want to add needs to be below the code that we added here,

7
00:00:31,950 --> 00:00:33,580
the layout.addview,

8
00:00:33,580 --> 00:00:39,070
and if you remember the activity lifecycle from a few videos ago, the onCreate function's called when the

9
00:00:39,070 --> 00:00:40,330
activity's launched.

10
00:00:40,330 --> 00:00:45,940
So this is a good place to initialize the YouTubePlayer, and is where we're going to actually put it.

11
00:00:45,940 --> 00:00:55,290
So we're going to type playerView.initialize parentheses, and it's going to be getString, then

12
00:00:55,290 --> 00:00:56,910
another set of parentheses. It's going to

13
00:00:56,910 --> 00:01:08,680
be R.string dot, then I'm going to select GOOGLE_API_KEY, closing parentheses comma this. So we've already got the

14
00:01:08,680 --> 00:01:12,280
code to add the YouTube, or add a YouTubePlayerView to the layout,

15
00:01:12,280 --> 00:01:17,440
so we just needed to add one line to initialize it. And we need to give it the Google API key that we

16
00:01:17,440 --> 00:01:22,810
got in the previous video, and you can see on screen we're doing that by passing the resource ID to the

17
00:01:22,810 --> 00:01:24,180
getString function.

18
00:01:24,180 --> 00:01:30,950
So that looks up the ID in the string resources, and then returns the string, in our case the key. And initialize

19
00:01:30,950 --> 00:01:34,720
also needs onInitializedListener object.

20
00:01:34,720 --> 00:01:41,200
Now our class, if you recall, implements that interface and we've generated the basic stubs for the interface functions,

21
00:01:41,200 --> 00:01:48,940
that's the onInitializationSuccess and onInitializationFailure functions you've got on lines 36 and 40. Then

22
00:01:48,940 --> 00:01:55,000
remember that an interface is just a contract. The interface defines some functions that are required,

23
00:01:55,000 --> 00:02:01,720
and anything claiming to implement that interface must provide implementations for the functions.

24
00:02:01,720 --> 00:02:07,940
So imagine a bee interface. The interface basically says "Hey, I'm a bee, I can buzz and I can make honey".

25
00:02:07,940 --> 00:02:14,110
Now when something implements the bee interface, it must be able to buzz, and it must be able to make honey.

26
00:02:14,110 --> 00:02:18,820
Now it's not good enough just to be able to buzz. If it just buzzes but doesn't make honey, then it's not

27
00:02:18,820 --> 00:02:20,240
a bee, it's a yellow jacket - 

28
00:02:20,240 --> 00:02:28,390
a wasp in Australia and the UK. Now our YouTubeActivity is a bee, or rather, it's a YouTubePlayer.OnInitialized

29
00:02:28,390 --> 00:02:30,220
Listener object.

30
00:02:30,220 --> 00:02:32,930
So in other words it implements the YouTubePlayer dot

31
00:02:32,930 --> 00:02:38,140
OnInitializedListener, and that means it has the functions that the interface defines. So we know that it

32
00:02:38,140 --> 00:02:43,960
must contain those functions, because Android Studio complained until we added them. Now if Android Studio

33
00:02:43,960 --> 00:02:47,410
hadn't complained, then our code still wouldn't have compiled.

34
00:02:47,410 --> 00:02:50,070
The compiler enforces that contract as well.

35
00:02:50,070 --> 00:02:57,010
Alright so our YouTubeActivity can be used wherever an object of type OnInitializedListener is needed.

36
00:02:57,010 --> 00:03:02,740
So anything that's given an instance of our YouTubeActivity class when it wants an OnInitializedListener,

37
00:03:02,740 --> 00:03:09,610
can be sure that our class will have an onInitializedSuccess and also an onInitializedFailure functions.

38
00:03:09,610 --> 00:03:11,350
Our functions don't do very much at the moment

39
00:03:11,350 --> 00:03:16,690
but at least calling them won't crash the program. We implement the interface and they do exist.

40
00:03:16,690 --> 00:03:21,690
So when a function needs an object of type YouTubePlayer.OnInitializedListener

41
00:03:21,690 --> 00:03:26,170
I can just pass 'this' for that parameter, and that's what I'm doing on line 33.

42
00:03:26,170 --> 00:03:31,600
So now that we've done that, the purpose of these two interface methods that we have to implement may become

43
00:03:31,600 --> 00:03:38,990
clearer. If the initialization is successful, the player will call our onInitializationSuccess method.

44
00:03:38,990 --> 00:03:43,430
If however it fails, our onInitializationFailure function gets called.

45
00:03:43,430 --> 00:03:47,600
So that way, a code can know whether it's OK to go ahead and play videos.

46
00:03:47,600 --> 00:03:52,250
Obviously if the initialization fails for some reason, then the videos won't play.

47
00:03:52,250 --> 00:03:57,140
So we're going to deal with the failure first, and we'll use that to notify the user that something's gone

48
00:03:57,140 --> 00:04:00,940
wrong by displaying a Toast message to the screen.

49
00:04:00,940 --> 00:04:05,420
Alright so there's quite a few things that can go wrong, and a quick peek at the source code of YouTube initialization

50
00:04:05,420 --> 00:04:09,440
results shows the various results that can be returned.

51
00:04:09,440 --> 00:04:14,070
So let's jump directly to the source. I'm going to hold down the command key because I'm on a Mac, hold down

52
00:04:14,070 --> 00:04:17,050
the Control key, otherwise, and click on down here the

53
00:04:17,050 --> 00:04:21,769
YouTubeInitializationResult in the parameter lists. Now click on that.

54
00:04:21,769 --> 00:04:27,240
So what we're interested in are the values of this Enum called YouTubeInitializationResult.

55
00:04:27,240 --> 00:04:28,790
You can see there's quite a few of them.

56
00:04:28,790 --> 00:04:33,560
So an Enum is basically a way to group Constants together into a type.

57
00:04:33,560 --> 00:04:38,200
Now there's a bit more to it than that, and as you can see, an Enum can contain code as well

58
00:04:38,200 --> 00:04:43,490
as just constants, but we're really only interested in these constant values at the start.

59
00:04:43,490 --> 00:04:47,000
Their names give an indication of the sorts of things that can go wrong.

60
00:04:47,000 --> 00:04:50,840
So the first one's easy - success means the initialization's succeeded,

61
00:04:50,840 --> 00:04:55,770
so we shouldn't see that in the failure callback function, but there's also code dealing with a network

62
00:04:55,770 --> 00:04:58,550
error, and an error connecting to YouTube itself.

63
00:04:58,550 --> 00:05:04,890
That's the ERROR_CONNECTING_TO_SERVICE as well as various codes concerning the

64
00:05:04,890 --> 00:05:07,160
YouTube service running on the device.

65
00:05:07,160 --> 00:05:13,010
Now if Google's YouTube Player isn't installed, then you can't use this API and those codes reflect that.

66
00:05:13,010 --> 00:05:16,820
So that's why we won't be able to test the finished app on an older emulator.

67
00:05:16,820 --> 00:05:21,090
We're going to have to use something that's got Google Play installed to run this app, and you saw in

68
00:05:21,090 --> 00:05:25,670
a previous section of this course, that we downloaded a version of the emulator that does support or

69
00:05:25,670 --> 00:05:29,420
does have released system images that have got Google Play.

70
00:05:29,420 --> 00:05:37,070
Now if you want more information on the detail of these error codes, I'll just bring up the browser and have a look.

71
00:05:37,070 --> 00:05:42,110
There's a link there, and you can find out more relating to specifically what they're all about.

72
00:05:42,110 --> 00:05:47,660
Now we could check to see which code we received, if there was an initialization failure, and display a suitable

73
00:05:47,660 --> 00:05:50,690
message, but Google have made things a bit easier for us.

74
00:05:50,690 --> 00:05:55,730
If we scroll past the summary, down here, of what these codes mean, there's a bit more detail on each one

75
00:05:55,730 --> 00:06:01,400
a bit further down, and for many of them it's just really elaborating what was in the summary table.

76
00:06:01,400 --> 00:06:07,920
Now let's just scroll down there and you can see that it starts talking about using getError dialogue or calling that, to get a localized error

77
00:06:07,920 --> 00:06:12,960
dialogue that'll enable the user to resolve the error. And that can be used if Google's YouTube Player

78
00:06:12,960 --> 00:06:15,110
has been disabled on the device,

79
00:06:15,110 --> 00:06:20,480
if it's not installed, which is the SERVICE_MISSING result code, or if it's out of date.

80
00:06:20,480 --> 00:06:24,920
So we could test for those three faults, and display the Google error dialogue,

81
00:06:24,920 --> 00:06:29,960
but it gets even easier than that, because if we scroll down even further, almost to the bottom of the page,

82
00:06:29,960 --> 00:06:35,120
there's a Boolean field there called isUserRecoverableError. Let's have a look at that,

83
00:06:35,120 --> 00:06:37,700
this one here, isUserRecoverableError,

84
00:06:37,700 --> 00:06:40,730
and that'll be true, if we should show the error dialogue.

85
00:06:40,730 --> 00:06:46,310
So armed with all that information we can write the code to deal with an initialization failure.

86
00:06:46,310 --> 00:06:51,200
So one thing that's not clear though in this documentation, is what the request code value is, that we

87
00:06:51,200 --> 00:06:53,310
should use when getting the error dialogue.

88
00:06:53,310 --> 00:06:58,460
Now Google do admit that sometimes their documentation isn't as helpful as it could be, and unfortunately this

89
00:06:58,460 --> 00:07:00,080
is one of those times.

90
00:07:00,080 --> 00:07:05,180
So I'm going to add another video at the end of this section, to show you how that request code's used,

91
00:07:05,180 --> 00:07:09,590
but fortunately, Google do provide a lot of sample code.

92
00:07:09,590 --> 00:07:14,060
So when you find yourself struggling to make sense of the documentation, have a look at the Google code

93
00:07:14,060 --> 00:07:20,810
samples, and life will be a lot easier. In fact the code we're about to use is almost identical to the on

94
00:07:20,810 --> 00:07:26,720
InitializationFailure callback, in a sample code that's included in the zip file we downloaded earlier

95
00:07:26,720 --> 00:07:28,080
in this section.

96
00:07:28,080 --> 00:07:32,900
Now hopefully the code generator will use more descriptive names for those parameters in future.

97
00:07:32,900 --> 00:07:38,460
And if you we back and have a look at the code. Alright so looking at this code now for the failure. 

98
00:07:38,460 --> 00:07:39,780
Hopefully in the future,

99
00:07:39,780 --> 00:07:45,420
in terms of these parameters, the first ones are YouTubePlayer.Provider object, provide us an

100
00:07:45,420 --> 00:07:50,070
interface that defines the initialize method. We'll call that to start the player, or

101
00:07:50,070 --> 00:07:56,520
we do call that to start the player in onCreate. The second parameter, that youTubeInitializationResult

102
00:07:56,520 --> 00:07:59,700
that we've just been looking at, or is that, that's this one here.

103
00:07:59,700 --> 00:08:04,560
So we're going to rename the parameters so that they reflect what they are, and add some Toast messages.

104
00:08:04,560 --> 00:08:05,190
So let's change that.

105
00:08:05,190 --> 00:08:11,560
So we're going to put, so instead of p zero, we'll call this one provider, and for the second one, instead of p one,

106
00:08:11,560 --> 00:08:21,460
let's go for youTubeInitializationResult. Let's just do that so we can see things a little bit easier.

107
00:08:21,460 --> 00:08:26,370
I'll get rid of the TODO not implemented any more, because we are implementing that now. Alright so let's start, we're going

108
00:08:26,370 --> 00:08:33,179
to start by typing val REQUEST_CODE equals zero,

109
00:08:33,179 --> 00:08:43,350
then if, then parentheses, youTubeInitializationResult.isUserRecoverableError. Then we're going

110
00:08:43,350 --> 00:08:53,260
to do youTubeInitializationResult.getErrorDialog, and the arguments will be this comma REQUEST_CODE 

111
00:08:53,260 --> 00:09:02,440
parentheses dot show. Otherwise I'm going to add an else, and the else is going to say val errorMessage is equal to.

112
00:09:02,440 --> 00:09:03,420
Let's put an error message here,

113
00:09:03,420 --> 00:09:06,200
this is the error message that we're going to pop up on the screen,

114
00:09:06,200 --> 00:09:18,350
"There was an error initializing the YouTubePlayer", let's make that all one word,

115
00:09:18,350 --> 00:09:28,120
and we'll put the error message, "youTubeInitializationResult". Then we'll do Toast.makeText parentheses, this comma

116
00:09:28,120 --> 00:09:36,770
error message, errorMessage comma Toast.LENGTH_LONG, that stays on the screen a bit longer, dot

117
00:09:36,770 --> 00:09:44,260
show. Now I'm going to come back to that request that the getError dialogue method wants, the request code, but I've created

118
00:09:44,260 --> 00:09:48,700
a constant so that we don't see the number 0 in the code and wonder what it's doing there.

119
00:09:48,700 --> 00:09:54,880
We then check if user isUserRecoverableError is true, and use Google's error dialogue to display a message

120
00:09:54,880 --> 00:09:59,980
to the user if it is. If it isn't, the code formats a string message to include the name of the result

121
00:09:59,980 --> 00:10:03,710
Enum and uses a Toast message to display it on the screen.

122
00:10:03,710 --> 00:10:06,250
Now I don't think we've used a Toast message before.

123
00:10:06,250 --> 00:10:11,110
That's the name given for one of those messages that appear on your phone then fade away after a while.

124
00:10:11,110 --> 00:10:15,990
It's a useful way to notify the user of something without distracting them, by making them click an

125
00:10:15,990 --> 00:10:21,400
OK button. So in other words they get to see the message but can carry on working without being interrupted.

126
00:10:21,400 --> 00:10:26,770
So to create one, we just call a static make text function. Now we have to give it a context, which is something

127
00:10:26,770 --> 00:10:28,030
we've been doing a lot,

128
00:10:28,030 --> 00:10:32,170
and the message that you want to show. And you can also choose to make it stay on the screen for a little

129
00:10:32,170 --> 00:10:34,030
shorter time or a bit longer,

130
00:10:34,030 --> 00:10:39,190
by using the Toaster.LENGTH_SHORT or Toast.LENGTH_LONG constants, and you'll see

131
00:10:39,190 --> 00:10:43,900
that appearing on the screen when we run the app. Alright but we have got two errors at this point.

132
00:10:43,900 --> 00:10:48,700
The parameters are declared as nullable types, and Kotlin doesn't let us go merrily calling functions

133
00:10:48,700 --> 00:10:53,980
on something that could be null. Now is it likely that this callback function will be called with null arguments?

134
00:10:53,980 --> 00:10:56,370
Probably not, but can we guarantee that?

135
00:10:56,370 --> 00:11:01,030
Well no we can't. The YouTube API library hasn't been changed for a long time,

136
00:11:01,030 --> 00:11:07,100
so I think it's unlikely that Google will add the atNoneNull and atNullable annotations to it.

137
00:11:07,100 --> 00:11:11,650
Of course I don't know what Google are planning so that's just a guess, but I'm guessing on the side

138
00:11:11,650 --> 00:11:16,600
of caution, and I'm not going to modify the function signature because I just can't be sure.

139
00:11:16,600 --> 00:11:22,450
This library isn't open source, so we can't easily check the source code to see if null can be passed as an argument

140
00:11:22,450 --> 00:11:27,910
or not. So we've got to work with what we've got. So the call to get error dialogue's easy.

141
00:11:27,910 --> 00:11:33,520
We're just going to use a safe call operator, when calling the dot getError dialogue and the show methods.

142
00:11:33,520 --> 00:11:38,750
So let's go ahead and add the safe call, two safe call operators.

143
00:11:38,750 --> 00:11:40,960
So the first one is youTubeInitializationResult.

144
00:11:40,960 --> 00:11:43,970
We want a questionmark in there, the safe call operator.

145
00:11:43,970 --> 00:11:47,980
Then we want to do exactly the same for the show as well.

146
00:11:47,980 --> 00:11:54,140
Now the condition above that, on line 45, that's not quite so obvious though, and that's because when we try to

147
00:11:54,140 --> 00:12:00,650
use a safe call operator, there, we still get an error. We get another error in fact,'Type mismatch,

148
00:12:00,650 --> 00:12:04,080
Required Boolean, Found Boolean, question mark'.

149
00:12:04,080 --> 00:12:08,630
And the reason for this is that the condition must evaluate to a Boolean,

150
00:12:08,630 --> 00:12:12,020
but we might have null, and we're using a nullable Boolean.

151
00:12:12,020 --> 00:12:16,070
Now the solution makes perfect sense but isn't very intuitive.

152
00:12:16,070 --> 00:12:20,030
In fact it looks like it involves doing something that programmers are taught not to do.

153
00:12:20,030 --> 00:12:22,020
So we compare it to true.

154
00:12:22,020 --> 00:12:27,230
Now let's just put the code in, then we'll talk about it, so down here we're going to add, at the end of the line, equals

155
00:12:27,230 --> 00:12:30,230
equals true, and that fixes the error.

156
00:12:30,230 --> 00:12:36,170
But as programmers were taught not to compare Booleans to true or false, because they are true or false,

157
00:12:36,170 --> 00:12:39,020
but remember that we're not dealing with a Boolean here.

158
00:12:39,020 --> 00:12:42,290
We've got a Boolean question mark, in other words a nullable Boolean.

159
00:12:42,290 --> 00:12:47,340
So consequently the equals equals true is acceptable and fixes the error.

160
00:12:47,340 --> 00:12:51,710
Now we could have performed an explicit null check as well, and that would also have worked,

161
00:12:51,710 --> 00:12:56,780
but I think this one, this solution's a little bit tidier, and because null curl equal true,

162
00:12:56,780 --> 00:12:59,930
we've also got an implicit null check in that condition.

163
00:12:59,930 --> 00:13:05,300
And in fact Kotlin's picked up on that, and if we have a look we've actually got a suggestion here, that the

164
00:13:05,300 --> 00:13:07,910
safe call operator on the next line is no longer needed.

165
00:13:07,910 --> 00:13:12,090
So we can actually remove both of them, so come over here and have a look, 'Unnecessary safe

166
00:13:12,090 --> 00:13:17,000
call on a non-null receiver of type YouTubeInitializationResult? 

167
00:13:17,000 --> 00:13:24,520
So consequently, we can actually now remove those. Alright so we've got that fixed.

168
00:13:24,520 --> 00:13:27,580
Alright, so I'm going to end the video here. In the next one,

169
00:13:27,580 --> 00:13:32,080
we need to put some work in to get the app ready to be running on the Google emulator.

170
00:13:32,080 --> 00:13:33,480
So I'll see you in the next video.

