Kotlin Upload Image From Camera To Server Android Example

kotlin splash screen, kotlin listview searchview, kotlin app intro slider, kotlin webview with progress bar, kotlin webview back forward navigation, kotlin parse json from url, kotlin login register android, kotlin upload image from gallery, kotlin upload image from camera, kotlin sqlite database, kotlin sqlite crud

I will write on Kotlin Upload Image From Camera To Server Android Example.

You will learn how to capture image from camera and then send it to the remote server (PHP-MySQL) using Kotlin in android app.

We will not use any external library to make http calls rather we will be dependent on the Multipart class.

Here, we will capture the image first and then will upload it to server, if you want to upload the image from your gallery read kotlin upload image gallery android example.

First of all, see the below images as an output of this example.

kotlin upload image from camera

 

kotlin upload image from camera

Writing PHP

To interact with server from android app, we need to write two php scripts.

First of all, make a php file named “config.php” and write the following code in it

<?php
$host="localhost";
$user="your username";
$password="your password";
$db = "your db name";
 
$con = mysqli_connect($host,$user,$password,$db);
 
// Check connection
if (mysqli_connect_errno())
  {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
  }else{  //echo "Connect"; 
  
   
   }
 
?>

Above file gas some common configuration lines.

Now make another PHP file like uploadfile.php and it should have below lines

<?php
 if($_SERVER['REQUEST_METHOD']=='POST'){
  	// echo $_SERVER["DOCUMENT_ROOT"];  // /home1/demonuts/public_html
	//including the database connection file
  	include_once("config.php");
  	  	
  	//$_FILES['image']['name']   give original name from parameter where 'image' == parametername eg. city.jpg
  	//$_FILES['image']['tmp_name']  temporary system generated name
  
        $originalImgName= $_FILES['filename']['name'];
        $tempName= $_FILES['filename']['tmp_name'];
        $folder="uploadedFiles/";
        $url = "https://www.demonuts.com/Demonuts/JsonTest/Tennis/uploadedFiles/".$originalImgName; //update path as per your directory structure 
        
        if(move_uploaded_file($tempName,$folder.$originalImgName)){
                $query = "INSERT INTO upload_image_video (pathToFile) VALUES ('$url')";
                if(mysqli_query($con,$query)){
                
                	 $query= "SELECT * FROM upload_image_video WHERE pathToFile='$url'";
	                 $result= mysqli_query($con, $query);
	                 $emparray = array();
	                     if(mysqli_num_rows($result) > 0){  
	                     while ($row = mysqli_fetch_assoc($result)) {
                                     $emparray[] = $row;
                                   }
                                   echo json_encode(array( "status" => "true","message" => "Successfully file added!" , "data" => $emparray) );
                                   
	                     }else{
	                     		echo json_encode(array( "status" => "false","message" => "Failed!") );
	                     }
			   
                }else{
                	echo json_encode(array( "status" => "false","message" => "Failed!") );
                }
        	//echo "moved to ".$url;
        }else{
        	echo json_encode(array( "status" => "false","message" => "Failed!") );
        }
  }
?>

Step 1. New Project With Kotlin

Go to your android studio and create a new project.

When you are doing this, make sure that you select empty activity as the default one and select Kotlin as the primary language.

Step 2. Gradle Changes

Open your build.gradle(Project: your project name) file and add the below line

maven { url 'https://jitpack.io' }

in the following structure

allprojects {
    repositories {
        google()
        jcenter()
}

So the final code block for build.gradle(Project: your project name) file is as the below

buildscript {
    ext.kotlin_version = '1.3.31'
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
        
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

That’s it for build.gradle(Project: your project name) file.

Now open your another gradle file which is build.gradle(Module: app) file.

In this file, write the below lines

  android{
        useLibrary  'org.apache.http.legacy'
    }
    packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }

in the root or parent level android { …. } tag.

Now, add the following lines

 implementation 'com.karumi:dexter:5.0.0'

    implementation group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.5.1'
    implementation('org.apache.httpcomponents:httpmime:4.3') {
        exclude module: "httpclient"
    }

inside dependencies { … } 

Here, first line is the dexter library which will help us to implement runtime permissions.

All other lines will help us to make http calls with Multipart.

So final source block for build.gradle(Module: app) file is as the following

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.uploadcamerakotlin"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    android{
        useLibrary  'org.apache.http.legacy'
    }
    packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    implementation 'com.karumi:dexter:5.0.0'

    implementation group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.5.1'
    implementation('org.apache.httpcomponents:httpmime:4.3') {
        exclude module: "httpclient"
    }

}

Step 3. Manifest

Now open your AndroidManifest.xml file and add the following lines in it.

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />

These lines are the permissions for read external storage, write external storage and for internet.

For first two permissions, we need to ask for runtime permissions because they are dangerous for user privacy.We will do this in the MainActivity.kt class later.

Step 4. Multipart Class

Now create a new class and give it a name like MultipartRequester.kt

Write down the below source code in MultipartRequester.kt file.

import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.os.AsyncTask
import android.util.Log
import android.widget.Toast
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.ContentType
import org.apache.http.entity.mime.MIME
import org.apache.http.entity.mime.MultipartEntityBuilder
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.params.HttpConnectionParams
import org.apache.http.util.EntityUtils
import java.io.File


class MultiPartRequester(
    private val activity: Activity, private val map: MutableMap<String, String>,
    private val serviceCode: Int, asyncTaskCompleteListener: AsyncTaskCompleteListener
) {
    private var mAsynclistener: AsyncTaskCompleteListener? = null
    private var httpclient: HttpClient? = null
    private var request: AsyncHttpRequest? = null

    init {

        // is Internet Connection Available...


            mAsynclistener = asyncTaskCompleteListener as AsyncTaskCompleteListener
            request = AsyncHttpRequest().execute(map["url"]) as AsyncHttpRequest


    }

    internal inner class AsyncHttpRequest : AsyncTask<String, Void, String>() {

        override fun doInBackground(vararg urls: String): String? {
            map.remove("url")
            try {

                val httppost = HttpPost(urls[0])
                httpclient = DefaultHttpClient()

                HttpConnectionParams.setConnectionTimeout(
                    httpclient!!.getParams(), 600000
                )

                val builder = MultipartEntityBuilder
                    .create()

                for (key in map.keys) {

                    if (key.equals("filename", ignoreCase = true)) {
                        val f = File(map[key])

                        builder.addBinaryBody(
                            key, f,
                            ContentType.MULTIPART_FORM_DATA, f.getName()
                        )
                    } else {
                        builder.addTextBody(
                            key, map[key], ContentType
                                .create("text/plain", MIME.DEFAULT_CHARSET)
                        )
                    }
                    Log.d("TAG", key + "---->" + map[key])
                    // System.out.println(key + "---->" + map.get(key));
                }

                httppost.setEntity(builder.build())

                val manager = activity
                    .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

                if (manager.memoryClass < 25) {
                    System.gc()
                }
                val response = httpclient!!.execute(httppost)

                return EntityUtils.toString(
                    response.getEntity(), "UTF-8"
                )

            } catch (e: Exception) {
                e.printStackTrace()
            } catch (oume: OutOfMemoryError) {
                System.gc()

                Toast.makeText(
                    activity.parent.parent,
                    "Run out of memory please colse the other background apps and try again!",
                    Toast.LENGTH_LONG
                ).show()
            } finally {
                if (httpclient != null)
                    httpclient!!.getConnectionManager().shutdown()

            }
            return null
        }

        override fun onPostExecute(response: String) {

            if (mAsynclistener != null) {
                mAsynclistener!!.onTaskCompleted(response, serviceCode)
            }
        }
    }

    private fun showToast(msg: String) {
        Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show()
    }

}

This class will help us to make http call to the remote server.

We will use the object of this class in the main activity.

Step 5. An Interface

Let us create a new kotlin class and give it a name like AsyncTaskCompleteListener.kt

Add the below lines in AsyncTaskCompleteListener.kt file.

interface AsyncTaskCompleteListener {
    fun onTaskCompleted(response: String, serviceCode: Int)
}

It is an interface and we will implement it in the main activity.

Step 6. Last Customization

We have reached at out last step. We will customize activity_main.xml and MainActivity.kt file in this step.

So, in your activity_main.xml  file, add the below code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btn"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="0dp"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Select or Capture Image" />

    <ImageView
            android:layout_width="300dp"
            android:layout_height="200dp"
            android:layout_gravity="center"
            android:layout_marginTop="20dp"
            android:scaleType="fitXY"
            android:src="@mipmap/ic_launcher"
            android:id="@+id/iv"/>

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="30dp"
              android:layout_marginLeft="30dp"
              android:text="Below is the URL of uploaded image"
              android:textColor="#000"
              android:textSize="20sp"
    />


    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:id="@+id/tv"
              android:layout_marginTop="20dp"
              android:layout_marginLeft="30dp"
              android:text="dddd"
              android:textColor="#000"
              android:textSize="20sp"
    />
</LinearLayout>

Above contains one button, one image view and two text views.

One text view is static and it will not change it’s text. Another text view will hold the URL of the uploaded image.

Image view will preview the uploaded image.

Now in your MainActivity.kt class, write down the following source snippet

import android.Manifest
import android.content.Intent
import android.graphics.Bitmap
import android.media.MediaScannerConnection
import android.net.Uri
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.example.uploadgallerykotlin.AsyncTaskCompleteListener
import com.example.uploadgallerykotlin.MultiPartRequester
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.*
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.karumi.dexter.Dexter
import com.karumi.dexter.listener.PermissionRequest
import org.json.JSONException
import org.json.JSONObject

class MainActivity : AppCompatActivity() , AsyncTaskCompleteListener {

    private var btn: Button? = null
    private var tv: TextView? = null
    private var imageview: ImageView? = null
    private val CAMERA = 1
    internal var uploadURL = "https://demonuts.com/Demonuts/JsonTest/Tennis/uploadfile.php"
    var arraylist: ArrayList<HashMap<String, String>>? = null

    override fun onCreate(savedInstanceState:Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        requestMultiplePermissions()

        btn = findViewById<View>(R.id.btn) as Button
        tv = findViewById<View>(R.id.tv) as TextView
        imageview = findViewById<View>(R.id.iv) as ImageView

        btn!!.setOnClickListener {
            val intent = Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)
            startActivityForResult(intent, CAMERA)
        }

    }

    public override fun onActivityResult(requestCode:Int, resultCode:Int, data: Intent?) {

        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == CAMERA) {
            if (data != null)
            {
                val contentURI = data!!.data
                try
                {
                    val bitmap = data.extras!!.get("data") as Bitmap
                    val path = saveImage(bitmap)
                    Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT).show()
                    imageview!!.setImageBitmap(bitmap)

                    uploadImage(path)

                }
                catch (e: IOException) {
                    e.printStackTrace()
                    Toast.makeText(this@MainActivity, "Failed!", Toast.LENGTH_SHORT).show()
                }

            }

        }

    }

    private fun uploadImage(path: String) {

        val map = HashMap<String, String>()
        map.put("url", "https://demonuts.com/Demonuts/JsonTest/Tennis/uploadfile.php")
        map.put("filename", path)
        MultiPartRequester(this, map, CAMERA, this)
    }

    override fun onTaskCompleted(response: String, serviceCode: Int) {

        Log.d("respon", response.toString())
        when (serviceCode) {
            CAMERA -> if (isSuccess(response))
            {
                val url = getURL(response)
                tv!!.text = url

                tv!!.setOnClickListener(View.OnClickListener {
                    val browserIntent = Intent(Intent.ACTION_VIEW)
                    browserIntent.data = Uri.parse(url)
                    startActivity(browserIntent)
                })

            }
        }

    }

    fun isSuccess(response: String): Boolean {

        try {
            val jsonObject = JSONObject(response)
            return jsonObject.optString("status") == "true"

        } catch (e: JSONException) {
            e.printStackTrace()
        }

        return false
    }


    fun getURL(response:String):String {
        var url = ""
        try
        {
            val jsonObject = JSONObject(response)
            jsonObject.toString().replace("\\\\", "")
            if (jsonObject.getString("status").equals("true"))
            {
                arraylist = ArrayList<HashMap<String, String>>()
                val dataArray = jsonObject.getJSONArray("data")
                for (i in 0 until dataArray.length())
                {
                    val dataobj = dataArray.getJSONObject(i)
                    url = dataobj.optString("pathToFile")
                }
            }
        }
        catch (e: JSONException) {
            e.printStackTrace()
        }
        return url
    }

    fun saveImage(myBitmap: Bitmap):String {
        val bytes = ByteArrayOutputStream()
        myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes)
        val wallpaperDirectory = File(
            (Environment.getExternalStorageDirectory()).toString() + IMAGE_DIRECTORY)
        // have the object build the directory structure, if needed.
        Log.d("fee",wallpaperDirectory.toString())
        if (!wallpaperDirectory.exists())
        {

            wallpaperDirectory.mkdirs()
        }

        try
        {
            Log.d("heel",wallpaperDirectory.toString())
            val f = File(wallpaperDirectory, ((Calendar.getInstance()
                .getTimeInMillis()).toString() + ".jpg"))
            f.createNewFile()
            val fo = FileOutputStream(f)
            fo.write(bytes.toByteArray())
            MediaScannerConnection.scanFile(this,
                arrayOf(f.getPath()),
                arrayOf("image/jpeg"), null)
            fo.close()
            Log.d("TAG", "File Saved::--->" + f.getAbsolutePath())

            return f.getAbsolutePath()
        }
        catch (e1: IOException) {
            e1.printStackTrace()
        }

        return ""
    }

    companion object {
        private val IMAGE_DIRECTORY = "/demonuts_upload"
    }

    private fun requestMultiplePermissions() {
        Dexter.withActivity(this)
            .withPermissions(
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
            .withListener(object : MultiplePermissionsListener {
                override fun onPermissionsChecked(report: MultiplePermissionsReport) {
                    // check if all permissions are granted
                    if (report.areAllPermissionsGranted()) {
                        Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT)
                            .show()
                    }

                    // check for permanent denial of any permission
                    if (report.isAnyPermissionPermanentlyDenied) {
                        // show alert dialog navigating to Settings
                        //openSettingsDialog()
                    }
                }

                override fun onPermissionRationaleShouldBeShown(permissions: List<PermissionRequest>, token: PermissionToken) {
                    token.continuePermissionRequest()
                }
            }).withErrorListener { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() }
            .onSameThread()
            .check()
    }

}

More Description

Let us read some more description on main activity’s code.

First of all, see the following lines

 private var btn: Button? = null
    private var tv: TextView? = null
    private var imageview: ImageView? = null
    private val CAMERA = 1
    internal var uploadURL = "https://demonuts.com/Demonuts/JsonTest/Tennis/uploadfile.php"
    var arraylist: ArrayList<HashMap<String, String>>? = null

First line is the object of the button class. Second is the object of the text view.

Third line is for the object of the image view. Fourth line is one variable which have 1 as a value.

Fifth line is also a variable which holds the URL which we need to call to upload the image.

Last line is making an arraylist of hash map.

In the onCreate() method, compiler will first execute requestMultiplePermissions() function.

Below is the code for requestMultiplePermissions() function.

 private fun requestMultiplePermissions() {
        Dexter.withActivity(this)
            .withPermissions(
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
            .withListener(object : MultiplePermissionsListener {
                override fun onPermissionsChecked(report: MultiplePermissionsReport) {
                    // check if all permissions are granted
                    if (report.areAllPermissionsGranted()) {
                        Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT)
                            .show()
                    }

                    // check for permanent denial of any permission
                    if (report.isAnyPermissionPermanentlyDenied) {
                        // show alert dialog navigating to Settings
                        //openSettingsDialog()
                    }
                }

                override fun onPermissionRationaleShouldBeShown(permissions: List<PermissionRequest>, token: PermissionToken) {
                    token.continuePermissionRequest()
                }
            }).withErrorListener { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() }
            .onSameThread()
            .check()
    }

Above method is using the dexter library. This method is implementing the runtime permissions for us.

We will ask for read and write external sources in this function.

Now focus on the following codes

  btn!!.setOnClickListener {
            val intent = Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)
            startActivityForResult(intent, CAMERA)
        }

Compiler will execute the above code when the user clicks the button. It will open the android device camera so that user can capture the image before he uploads it.

When the user captures the image, compiler will call onActivityResult() method.

 public override fun onActivityResult(requestCode:Int, resultCode:Int, data: Intent?) {

        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == CAMERA) {
            if (data != null)
            {
                val contentURI = data!!.data
                try
                {
                    val bitmap = data.extras!!.get("data") as Bitmap
                    val path = saveImage(bitmap)
                    Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT).show()
                    imageview!!.setImageBitmap(bitmap)

                    uploadImage(path)

                }
                catch (e: IOException) {
                    e.printStackTrace()
                    Toast.makeText(this@MainActivity, "Failed!", Toast.LENGTH_SHORT).show()
                }

            }

        }

    }

First of all, compiler will create the bitmap from the data. After this, it will use saveImage() method to save image in the external storage.

After this, it will set this image into the image view.

Below is the code lines for saveImage() method.

  fun saveImage(myBitmap: Bitmap):String {
        val bytes = ByteArrayOutputStream()
        myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes)
        val wallpaperDirectory = File(
            (Environment.getExternalStorageDirectory()).toString() + IMAGE_DIRECTORY)
        // have the object build the directory structure, if needed.
        Log.d("fee",wallpaperDirectory.toString())
        if (!wallpaperDirectory.exists())
        {

            wallpaperDirectory.mkdirs()
        }

        try
        {
            Log.d("heel",wallpaperDirectory.toString())
            val f = File(wallpaperDirectory, ((Calendar.getInstance()
                .getTimeInMillis()).toString() + ".jpg"))
            f.createNewFile()
            val fo = FileOutputStream(f)
            fo.write(bytes.toByteArray())
            MediaScannerConnection.scanFile(this,
                arrayOf(f.getPath()),
                arrayOf("image/jpeg"), null)
            fo.close()
            Log.d("TAG", "File Saved::--->" + f.getAbsolutePath())

            return f.getAbsolutePath()
        }
        catch (e1: IOException) {
            e1.printStackTrace()
        }

        return ""
    }

This method uses bitmap to save the image.

After saving the image, compiler will call uploadImage() method to upload the image to the server.

Following is the code block for uploadImage() method.

 private fun uploadImage(path: String) {

        val map = HashMap<String, String>()
        map.put("url", "https://demonuts.com/Demonuts/JsonTest/Tennis/uploadfile.php")
        map.put("filename", path)
        MultiPartRequester(this, map, CAMERA, this)
    }

Compiler will first create the hashmap. Then it will add two maps in it. One is for URL to the PHP web service and another is for path to the image.

Here, We need to implement an interface to this main activity. See the  below line

class MainActivity : AppCompatActivity() , AsyncTaskCompleteListener

So if we implement this interface, we need to write a method onTaskCompleted().

Compiler will run this onTaskCompleted() method when system has uploaded the image to the server and also had get the JSON response.

Following is the code for onTaskCompleted() method

 override fun onTaskCompleted(response: String, serviceCode: Int) {

        Log.d("respon", response.toString())
        when (serviceCode) {
            CAMERA -> if (isSuccess(response))
            {
                val url = getURL(response)
                tv!!.text = url

                tv!!.setOnClickListener(View.OnClickListener {
                    val browserIntent = Intent(Intent.ACTION_VIEW)
                    browserIntent.data = Uri.parse(url)
                    startActivity(browserIntent)
                })

            }
        }

    }

In this method, compiler will fetch the URL to the uploaded image from the JSON response.

Then it will set the text value of a text view as this URL. Now there is on click implementation in this method for text view.

Meaning is that, when the user clicks the text view, compiler will open the uploaded image into the web browser.

Download Code For Kotlin Upload Image From Camera

https://github.com/demonuts/Kotlin-Upload-Image-From-Camera-To-Server-Android-Example