How to Build a Camera App With CameraX - Taking Photos

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys um welcome back to a new Android video if you wanted Hardware tutorials and you will get Hardware tutorials because on this video you will learn about the camera X Library on how you can integrate a camera feed directly into your app and this will look something like this that you can really see directly inside of your Android device how messy your workplace is at home and how bad you are at cable management but you can also luckily switch the camera so you don't even need to look at that as you can see we can then hit the middle button to take a photo and all these photos will appear in a little Gallery we have here that is only an in-app Gallery so not a real stored gallery on the on the device's storage I'll explain in a moment why I decided to do so but what you can also do is you can record a video with the bottom right button and then that will actually be stored on the user's device and this will not only be one video these will be three videos which will all be related to camera X and will cover the core functionality of it so on the first video you will learn how you can actually integrate this camera feed into your amp how you can take photos and then display these photos in the next video you will then learn how you can capture videos with camera X and that last but not least which will probably be the coolest power so definitely watch till then we will integrate AR AI into our app so you will really learn something about image analyzing and image processing that we really go through frame by frame analyze these with an AI model in order to recognize landmarks in your personal country but in order to get there you just need to learn a bit about the camera X and Basics so we can do something very cool with it at the end if you want to follow along then let's dive into Android Studio please take a look at the GitHub repository which I've Linked In the description because that includes some initial dependencies we're going to need on the one hand this extended material icons one so we can just get more different material icons for our app but most importantly this camera ax dependencies which I've included here make sure to use the same version as I do so you can follow along and before I want to start some code I want to talk about when you actually need camera X for your app so if you have an app where the user needs to take a photo for example which you need in the app of the ward or you have an app where the user needs to record a video then in and of itself don't need camera x no you can just do that with an activity result because your user likely has a camera app on their device your user likely has an app on their device they can record a video with so you can just launch or let the user launch this other app record the video and then get the video in your app so if that's all you need ignore camera X it also has the advantage that you don't need to request any camera recruit audio permission directly in your app because it's only the other app that requires these permissions but when do you need camera X down camera X is needed whenever you need to directly integrate a camera feed into your app so think of Instagram for example where you can just record Instagram stories directly in the app Instagram does not launch your device's camera app because then that would be pretty bad because the user needs to leave the Instagram app in order to record a video no they want to keep the users in the app for as long as possible so they have an integrated camera which they have full control over so you can add filters you can change the audio maybe photo video recording you can stickers all that is only possible if you integrate it with a camera X directly at least on the Android side or at least a comparable way there are older versions of camera X which are camera and Camera 2 but camera acts as the newest one so whenever you want full access over the device's camera inside of your app and you don't want the user to leave the app and then follow this video because this will be crucial to learn how to implement this but I think I talked enough let's dive into coding and the first thing we need are of course permissions we are on Android we need permissions and especially for camera and recording audio we need to runtime permissions we need explicit approval from the user for that and in order to do that we first of all need to declare these in our manifest so right up here we say we have a user's permission on the one and for the camera access and let's also include the one for recording audio so I don't forget it in the next video but obviously for taking a photo we we don't need this record audio permission just phone making a video we can then hover over this user's permission because Android studio also wants us to add this user's feature tag we just declares hey we have an app that requires the app's camera those might be helpful at some point when your app is in Google Play So users can see which features and which Hardware your app requires but that's already enough for the Manifest let's dive into main activity and here we first of all want to request these permissions for that I want to have a little companion object in which we specify which permissions we have so I don't know camera X permissions for example which is just an array of on the one hand from manifest make sure to use the Android One manifest.permission camera and one for recording audio these other permissions you want to request and we can then have a function we can use to check whether we have these permissions or not so private function has required permissions obviously return a Boolean and then we're going to return camera X permissions that all so we will go over all these permissions in this array and we now want to check if we do have each single permission so context combat check self permission we can pass our replication context and we want to pass the permission we want to check if we have it and then check if that's actually equal to package manager whoops package manager adopt permission granted if that's the case for all these permissions in our array then we know we have the required permissions so I wanted to go up here and on create check if we don't have the required permissions because in that case we want to request this of course and we do this with activity combat request permissions and we say this for the activity we pass our camera X permissions so we will request all these and the request code is whatever you want to use here one little note here this is of course not a real permission handling like you would do in a normal app with a permission rational with also handling when the user declines that that is a whole topic on its own on Android I have a separate video about that but here I really want to keep the video focused on camera X so we'll just assume that the user accepts these permissions but if you maybe want me to make a real camera app at some point with more features which is just a full app which deals with these things like permission handling which also stores the images on a real device on the real storage then just let me know that in the comments what kind of app you would like to see that requires camera X and I would be very happy to do it at some point so what is now the first thing we want to do here for array UI now we know we have the permissions so we can start implementing our camera feed and if we take a look here in the app where you can see my beautiful lamp but apart from this lamp what I also want to have is a so-called bottom sheet scaffold because the gallery I've implemented that with a little bottom sheet here and that of course needs a scaffold to be attached to and that is what we're going to start with so we will have a bottom sheet scaffold and here we first of all have the sheet content so the content we want to have on the bottom sheet we will get to that in a moment we also want to attach a scaffold state so let's have a scaffold state which is equal to remember bottom sheet scaffold State and I think we need to add this experimental annotation like with everything in Android so I'll enter and add that and then we can add this scaffold State here in our function and by default this bottom sheet actually Peaks a little bit which I don't want so I don't want that it Peaks by default so we want to set the sheet Peak height to 0 DP like this then the scaffold of course has some content here we also get some padding padding values which you can apply to the root composable here in this bottom sheets scaffold and what do we now want to put in here if we take a look at our app then I actually just want to have a box which is the root composable of our screen in this box we will put the so-called preview view which just shows the camera feed and that we can take a look at the icons so we want to range one icon at the top left and the other ones in a row at the bottom so that is how this will work pretty simple UI let's get started with creating this box the modifier is modifier film exercise of course want to fill the whole screen and then we can add the padding which we get from our bottom sheet scaffold alright so what needs to be inside this box first of all what we want to have is of course our preview feed and I think that is uh what excites you the most because that is the core of camera X camera X does not support jetpack compose out of the box yet but we can very easily still use it with the help of the Android view composable so what we want to do is want to go to a root package create a new Quantum file called camera premium for example make that a file critically imposible in here called that camera preview and what does that need in form of parameters on the one hand we don't have a so-called controller which is a life cycle camera controller and this will really be the core of our camera X feed because with this controller we can completely control what is displayed so front camera back camera what we do without taking a photo capturing a video so we need to pass that and Link this to the preview view which we will Implement in here and now we're going to have a modified just as usual and this will actually not be a lot of code so we just want to have an Android view which is needed when we want to have an older view so from the XML view system I want to use that in Jetpack compose then we use a factory which is just a Lambda in which we create that all of you which in this case is a preview view you can see that comes from the camera library and here we can pass it so the contacts in order to create that we can then say apply to apply some changes to this view on the one hand we want to link this controller we passed so this so the preview dot controller is equal to the controller we passed and now we say a controller that bind to lifecycle which will then also listen to lifecycle changes um to properly show the camera or freed up when it's not needed anymore and here we need to pass the lifecycle owner we can get that uncomposable up here by saying well lifecycle owner is equal to local lifecycle unordered at current and then we pass that in here we also want to make sure that we pass in the modifier and that's it that's how we can use the camera feed India by compose of course you can do much more customizations here you can see um there are a lot of fields which we don't need here um so if you need some customizations take a look at this preview you can configure it here and also make sure that in case something you use something in this Android view composable which could update that would have an effect on the preview view then you also want to overwrite or rather use the oops the update Lambda which will be triggered when there is a change in compose state in order to also update the preview view but here our lifecycle camera controller will never change at least during one life cycle so we don't really need that and reattach it and these kinds of things okay let's go back to main activity and then Implement our camera preview here now we of course need to pass this lifecycle camera controller for that I want to go up here and create this well controller you want to put this in a remember block so um that does not get recreated on a re-recomposition that would be terrible and in here we would have a lifecycle camera controller which requires the context so you can just pass the context if you are not in the activity you can of course also get the contacts before with a local context that current and then oops we also want to say apply here and what we want to do is we want to say set use cases that enabled use cases so with this function we basically enable everything we want to be able to use in in combination with this preview feed so there are three of these use cases in total on the one hand taking a picture on the other hand capturing a video and on the other hand performing some image analysis and I would recommend to only enable what you really need so in our case here this is a camera controller dot image capture or camera control oops camera controller a dot video capture we're not going to need any image analysis and that is what we will do in the separate app for what I mentioned with AI we will really process frame by frame and check if we can recognize some kind of landmark on it but that will be a separate app and not be done inside of this one here cool now we have a controller which you can pass here like this and the modifier would of course modifier filmax size and if we launch this we should already be able to see some form of camera feed we won't be able to switch the cameras yet we'll be able to take a photo yet and especially not see any photos but we should be able to see a camera feed after accepting the permissions of course that is something we need to do initially you can see just while using the app while using the app and then after we relaunch the app we should now always have access to the permissions so as you can see there is our camera feed very cool let's move on the next thing I'd like to do is to have the button to switch the cameras which we can put below this camera preview that'll just be an icon button and when we click on this we want to switch the camera we also want to have content for this of course which is just whoops which is just an icon um that takes in an image of actor that will be icons default camera switch content description can be I don't know switch camera and when we click on this we can get access to our controller and actually change the camera selector two well if we are currently seeing the front camera to switch to the back camera and vice versa so if the controller camera selector is equal to camera controller back camera then we want to switch to camera selector front camera and else camera selector back camera that is what you want to do um I also like to offset this a little bit so it's not completely in the top left so modifier is modifier that offset and we offset this by 16 DP and 16 DP if we then relaunch this we should be able to see that we can switch our camera you can see there is a button and if I click this then there I am very cool you can see how easy that actually can be done let's next take a look at how we can take a photo and for that I want to go below this switch camera button and add a row which will be displayed at the bottom of our box so modifier modifier film x width we want to align it at the bottom center and we want to add some padding of let's say 16 DP and this row well actually on the one hand have a horizontal arrangement of arrangement dot space Branch so we just distribute the icon buttons a little bit and in here we can then add an icon button on the one hand for our gallery to open our bottom sheet so here on click and this will have an icon image Vector icons default photo and the condo description will be open gallery something like this and then we can take this button copy it paste it down here and this will be to take a photo so the icon will be photo camera and the content description will be take photo when we click this photo camera button what do we want to do well for that I want to make a little helper function because that's a bit more code than just switching the camera so let's add this down here private function take photo this needs our controller so to pass this here and this also takes a Lambda on photo taken this Lambda will give us the photo inform of a bitmap and we can then do whatever we want with it and in here in the end that's really only just a one function call but we need to pass a call back to that which we call some more lines so I want to say controller that take picture here for most of these camera X related functions we need to have a circle executor which just contains information about which thread this is going to be executed on here we can pretty much always just pass context combat get main executor for these UI related things and we pass in application context and then here for the second parameter we need a callback which is an on image captured callback like this and in here we can now react to whatever happened on the one hand so I hit command o by the way Ctrl o in the end we're going to be able to react to success events and error events so when capturing the image was a success we get this here in in form of an image proxy so that just contains some more information about the image like the rotation and we could now say on photo taken we pass in our image which is not a bitmap yet but there is a function to bitmap and then we have that image as a bitmap if there's an error we can also just uh say log dot e we say I don't know camera as a tag and then we say uh couldn't take photo and we pass in our exception so that should already be enough to take a photo but it doesn't help us if we can take a photo but not display it then we still don't see that everything worked so we also need to implement our little preview which we can do in a separate composable so photo bottom sheet content just a new file like this and this will take in a list of bitmaps you want to display in the bottom sheet content like this and a modifier as usual cool inside here this will be nothing else than a lazy staggered lazy vertical staggered Grit and the columns are staggered grid cells dot fixed so I'm going to have two columns of photos and let's also add some spacing between these photos so horizontal Arrangement is Arrangement spaced by 16 DP Alt Enter to import DP the vertical item spacing should be 16 DP as well and the padding values of the content padding will be padding values 16dp so this will be the horizontal spacing vertical spacing and the padding at the very um at the very edges of this lazy vertical staggered grid we then want to pass in or modifier and here we can then just have an items block that takes in a list of items and for each bitmap we want to have one item whoops which will just be image composable that takes in an image bitmap so the bitmap is equal to our bitmap as image bitmap so we convert that Android bitmap to a compose bitmap and then the content description can be nulled here and I just want to clip this a little bit so it looks nicer so the modifier is modified clip of a clip rounded Corner shape and pass in 10 DP if this loose is empty I would like to display the little text so if bitmaps is empty then we just want to have a little box modifier is modifier.padding 16dp for example we say the content alignment is Center and in this box we then display the text so text um no photos have or there are no photos yet and else so if there are photos we do display our lazy standard grid cool that that's our bottom sheet content which you can use in main activity here for the sheet content photo bottom sheet content bitmaps is uh well where do we get our bitmaps list from that's actually the only state we really need in our app so that's creative model for that so it also survives screen rotations new file main view model view model and in here I will use a state flow underscore bitmaps mutable State flow which contains an empty list by default which is a list of bitmap and then we have a public version of that which is underscore bitmaps as state flow and if we then take a photo on take photo we get a new bitmap which we want to add to this state flow so bitmaps.value plus equals or new bitmap then we update our state this will update our list and then we see this in our bottom sheet as well so here let's get a reference to oops what was that let's get a reference to our view model is equal to view model we don't have the composable for that we could initialize the view model here in our activity but I would like to add the dependency for that let's go to build it Gradle module app duplicate one of these dependencies here and I think we should get suggestions for that I think that is life's uh Android X life cycle runtime live data or is it viewmodel here this Android X lifecycle of your model compose dependency let's add that let's synchronize and then we should have access to initializing a view model in a composable let's take a look um is it this one because it doesn't highlight that as a composable this should be a main view model yes but that seems to work yes that's the composable function very cool so now we can use this um to get the bitmap state by viewmodel bitmaps collect as state we could also actually use collect as statewood lifecycle which would be even more correct um but I don't want to add another dependency here I have a separate video about that explaining what that would do in this case actually nothing well let's add our bitmap state to our photo bottom sheet content do we need something else I don't think so maybe just make sure that we fill the hole with um with the modifier film x width and that should be everything to display photos we now of course need to trigger rotate photo function for Icon button actually not this one this one here when we take a photo I want to say take photo the controller is just our controller we passed and the on photo taken Lambda will be delegated to a review model on take photo which will then update our state that will update our list and everyone is happy we also need to open our bottom sheet for that we need a little core routine scope otherwise that won't work so valve scope remember correcting scope and with a scope we can then open the bottom sheet so scope.launch and we say bottom sheet what is it little scaffold State bottom sheet State DOT expand when we click this button and I think this should be everything we need in order to take photos and to see which photos we've taken so if we launch this app and take a look in here there we are oh no there we are cool we do have our switch camera button which we've tried before that still works we can open our bottom sheet tells us there are no photos yet and if we take a photo click here then nothing crashes that is good if we open this then there is a photo but you will notice this actually rotated so we've taken a photo here in portrait mode but this is effectively landscape mode so you actually need to rotate that but how do we do that previously I've taught you that with this image proxy down here we also get access to the rotation degrees of that photo so we can see image dot image info that rotation degrees we can now use that to rotate the image yeah so that we can actually also see how it really looks like how do we do that we just need to create another bitmap here in this uncapture success Lambda or function and for that we can use a so-called Matrix sounds super complex but it's in the end just something we can use to transform an image and it's really simple in the end so is equal to a new Matrix and want to apply posting or rotate so we just want to rotate all the numbers in that Matrix based on our rotation degrees so image image info rotation degrees.2 float and then we can use this Matrix to get a rotated bitmap which is bitmap.create and here we have tons of overloads we want the overload that takes in a matrix this one here so we say okay first of all the bitmap we want to rotate this image to bitmap then acts as 0 Y is zero the height is at the width is image and width and the height is image.height The Matrix is our Matrix and the filter can just be true and there we go we have our rotated bitmap which you can then pass to a Lambda rotated bitmap and if we now try this again take a look here then we should see that we do have a fine rotation let's again take the same photo like this open this and you can see now it's actually also in the same format we recorded it in you can see it's actually mirrored if if you don't want that for the front camera you can also use this Matrix to post a scale and say you want to scale it based on the factor minus one F and one F so this would mirror it on the x-axis but not on the y-axis but that's only a problem for the front camera you can use the back camera that is not an issue anymore so you would also need to check what the what kind of camera the controller is currently using feel free to play around with that at home I'll leave it as it is I'm happy that we have a camera app here and that we can see some photos let's also try what happens if we switch the camera again and have a very cool photo here open that works well if we rotate our device then take a photo we should also be able to see everything right here yes and you can see that was actually in landscape mode so very cool awesome awesome we are able to take photos directly inside of our app but we're not done yet because the next video you will learn how you can record videos with the same setup definitely don't miss that and if you are interested in more advanced Android premium courses which will really prepare you for the industry as an developer then check the first link in this of this description because I have a bunch of these courses where I really packaged all my Android related knowledge together so you can get prepared in the fastest time possible thanks for watching you'll find the final source code below as well and I will see you back in the next video about recording videos and then finally we'll get to AI thanks for watching have an amazing rest of your week see you back in the next video bye bye foreign [Music]
Info
Channel: Philipp Lackner
Views: 35,378
Rating: undefined out of 5
Keywords:
Id: 12_iKwGIP64
Channel Id: undefined
Length: 29min 35sec (1775 seconds)
Published: Wed Oct 04 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.