================ Using The Camera ================ Android provides full access to the device camera hardware. In this worksheet, the camera will be used to capture photos, capture videos and scan QR codes. Capture Photos ============== #. Create a new empty project, and remove the *Hello World* TextView in :file:`activity_main.xml`. #. Since the application requires using camera, put a `` tag in :file:`AndroidManifest.xml`, this advertise that this application depends on having a camera: .. code-block:: xml #. Now, change the layout from ``ConstraintLayout`` to ``RelativeLayout``, then add a ``button`` and a ``imageView`` to the layout at a suitable position. #. Then add a ``setOnClickListener`` for the button which will invoke the function that takes a photo with a camera app. .. code-block:: kotlin takePic.setOnClickListener{ dispatchTakePictureIntent() } #. To delegate actions to other applications, in Android it invokes an ``Intent`` that describes what you want done. This process involves three pieces: the intent, a call to start the external Activity, and some code to handle the image data when returns to your activity. Here's a function that invokes an intent to capture a photo: .. code-block:: kotlin val REQUEST_IMAGE_CAPTURE = 1 private fun dispatchTakePictureIntent(){ val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) if (cameraIntent.resolveActivity(packageManager) != null){ startActivityForResult(cameraIntent,REQUEST_IMAGE_CAPTURE) } } ``resolveActivity()`` returns the first activity component that can handle the intent, it protects the ``startActivityForResult()`` method, because if ``startActivityForResult()`` is called using an intent that no app can handle, the app will crash. So as long as the result is not null, it's safe to use the intent. #. To get the thumbnail, Android Camera application encodes the photo in the return Intent delivered to ``onActivityResult()`` as a small Bitmap in the extras, under the key ``data``. The following code retrieves this image and displays it in an ImageView: .. code-block:: kotlin override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { super.onActivityResult(requestCode, resultCode, intent) if (resultCode == RESULT_OK){ if(requestCode == REQUEST_IMAGE_CAPTURE ){ val imageBitmap = intent?.extras?.get("data") as Bitmap imageView.setImageBitmap(imageBitmap) } } } #. The following screenshots show how the app should work and what the results look like: .. figure:: take_photo.jpg :scale: 50 % :align: center Capture Videos ============== #. Add another ``button`` and a ``videoView`` to the layout at a suitable position, then add a ``setOnClickListener`` for the button which invoke ``dispatchTakeVideoIntent()`` function. #. Similarly to ``dispatchTakePictureIntent()``, we invoke an Intent: .. code-block:: kotlin val REQUEST_VIDEO_CAPTURE = 2 private fun dispatchTakeVideoIntent(){ val takeVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE) if (takeVideoIntent.resolveActivity(packageManager) != null){ startActivityForResult(takeVideoIntent,REQUEST_VIDEO_CAPTURE) } } #. The Android Camera application returns the video in the ``Intent`` delivered to ``onActivityResult()`` as a ``Uri`` pointing to the video location in storage. The following code retrieves this video and displays it in a ``VideoView``: .. code-block:: kotlin else if (requestCode == REQUEST_VIDEO_CAPTURE && intent != null){ videoView.setVideoURI(intent.data) videoView.start() } #. To display only photo or video at one time, ``setVisibility()`` could be used to set one of them visible as a time. For example, the following code could be written when displaying video only: .. code-block:: kotlin imageView.setVisibility(View.INVISIBLE) videoView.setVisibility(View.VISIBLE) Similar things could be done when displaying photos. #. The output is similar to capture photos. Scan QR Code ============ This app scans the barcode and QRcode using zxing library. #. Update ``build.gradle(Module:app)`` file, add dependency .. code-block:: groovy implementation 'com.journeyapps:zxing-android-embedded:3.6.0' #. Add another ``button`` and a ``textView`` to the layout. The ``textView`` is used to display the content of the QR code. #. Add a ``setOnClickListener`` for the button, and add the following code to initiate scan: .. code-block:: kotlin IntentIntegrator(this).initiateScan() #. Now, parse the result in ``onActivityResult`` and display the result if it is not *null* .. code-block:: kotlin val scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent) else{ if (scanningResult != null){ qrResult.setText(scanningResult.contents.toString()) } } #. The scanning screen and result screen are shown below. .. figure:: scan_qr.jpg :scale: 50 % :align: center #. Here is a QR code with message *"hello world"*. .. figure:: hello_world_qr.jpg :scale: 40 % :align: center