To use Google Low Light Boost, you'll need a [*low light boost client*](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient).
You can use
the client to check if the low light boost module is installed, and to check
whether Google Low Light Boost is supported by the device and camera your app is
running on. You'll also use the client to create a [`LowLightBoostSession`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostSession).
([You'll use the session](https://developer.android.com/media/camera/lowlight/low-light-boost-gp/use-session) to turn low light boost on and off.) You can also
set up a listener to receive callbacks when low light boost is active.
| **Note:** The Google Low Light Boost APIs are provided by Google Play services. See the [Google Play services documentation](https://developers.google.com/android) for information on how to set up and call its APIs.

`LowLightBoostClient` methods don't signal success or failure directly. Instead,
they return a [`Task`](https://developers.google.com/android/reference/com/google/android/gms/tasks/Task) object. You use a `Task` to set up success and failure
listeners. This lets the methods signal success or failure asynchronously, which
is necessary since the methods need to communicate with Google Play services.

## Dependencies

### Kotlin

    dependencies {
      val low_light_boost_version = "16.0.1-beta04"
      implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.2")
      implementation("com.google.android.gms:play-services-base:18.7.0")
      implementation("com.google.android.gms:play-services-camera-low-light-boost:${low_light_boost_version}")
      implementation("com.google.android.gms:play-services-tasks:18.3.0")
    }

### Groovy

    dependencies {
      def low_light_boost_version = "16.0.1-beta04"
      implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.2'
      implementation 'com.google.android.gms:play-services-base:18.7.0'
      implementation 'com.google.android.gms:play-services-camera-low-light-boost:${low_light_boost_version}'
      implementation 'com.google.android.gms:play-services-tasks:18.3.0'
    }

`LowLightBoostClient` is provided by the Google Play services
[`com.google.android.gms.cameralowlight`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/package-summary) package. See the Google
Play services documentation for information on [accessing Google Play services
APIs](https://developers.google.com/android/guides/api-client).

## Create a client

You need a low light boost client to do anything else. The following code
creates a client:  

### Kotlin

    val lowLightBoostClient = LowLightBoost.getClient(context)

### Java

    LowLightBoostClient lowLightBoostClient = LowLightBoost.getClient(context);

### Key points about this code

- The [`LowLightBoost`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoost) class provides the static method [`getClient`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoost#getClient(android.content.Context))%7B:.external%7D(), which returns an instance of `LowLightBoostClient`.

## Check if low light boost is supported

Once you have a client, you can check if low light boost is supported by the
device the app is running on. The following code checks if low light boost is
supported:  

### Kotlin

    launch {
      try {
        // Await the result of the Task in a non-blocking way
        val isSupported: Boolean = lowLightBoostClient
          .isCameraSupported(cameraId).await()
        Log.d(TAG, "isCameraSupported: $isSupported")
        if (isSupported) {
          // Create the low light boost session here
        }
      } catch (e: Exception) {
        Log.e(TAG, "isCameraSupported failed", e)
      }
    }

### Java

    lowLightBoostClient
      .isCameraSupported(cameraId)
      .addOnSuccessListener(
        lowLightBoostExecutor,
        (isSupported) -> {
          Log.d(TAG, "isCameraSupported: " + isSupported);
          if (isSupported) {
            // Create the low light boost session here
          }
        )

### Key points about this code

- `cameraId` is assumed to be [the ID of a Camera2
  camera](https://developer.android.com/media/camera/camera2), created elsewhere.
- [`LowLightBoostClient.isCameraSupported()`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient#isCameraSupported(kotlin.String)) checks whether the Camera2 camera supports low light boost. In some cases, a device might support low light boost but one of its cameras might not, so you need to check both.
- The method `LowLightBoostClient.isCameraSupported()` returns a [`Task`](https://developers.google.com/android/reference/com/google/android/gms/tasks/Task) object. You use this object to set up success and failure listeners. [Create
  the low light boost session](https://developer.android.com/media/camera/lowlight/low-light-boost-gp/use-session) inside the success listener.

## Check if the low light boost module is installed

Once you have a client, you can confirm whether the low light boost module is
installed on your device. The following code checks if the module is installed:  

### Kotlin

    // Handle the Google Play services Task API with Kotlin coroutines
    // (kotlinx-coroutines-play-services)
    launch {
      try {
        val isInstalled: Boolean = lowLightBoostClient
          .isModuleInstalled(context).await()

        if (isInstalled) {
          Log.d(TAG, "Module is installed")
          try {
            openCamera(cameraId)
          } catch (e: CameraAccessException) {
            Log.e(TAG, "Failed to open camera", e)
          }
        } else {
          Log.d(TAG, "Module is not installed")
          launchInstallRequest()
        }
      } catch (e: Exception) {
        Log.e(TAG, "Failed to check module availability", e)
      }
    }

### Java

    lowLightBoostClient
      .isModuleInstalled(context)
      .addOnSuccessListener(
        (isInstalled) -> {
          if (isInstalled) {
            Log.d(TAG, "Module is installed");
            try {
              openCamera(cameraId);
            } catch (CameraAccessException e) {
              Log.e(TAG, "Failed to open camera", e);
            }
          } else {
            Log.d(TAG, "Module is not installed");
            launchInstallRequest();
          }
        })
      .addOnFailureListener(
        (e) -> {
          Log.e(TAG, "Failed to check module availability", e);
        });

### Key points about this code

- This code opens a camera session connecting to the camera identified by `cameraId`. For more information, see the [Camera2
  documentation](https://developer.android.com/media/camera/camera2).
- The method [`LowLightBoostClient.isModuleInstalled()`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient#isModuleInstalled(android.content.Context)) returns a [`Task`](https://developers.google.com/android/reference/com/google/android/gms/tasks/Task) object. You use this object to set up success and failure listeners.
- Use `Task.addOnSuccessListener()` to set up a listener that's called if the call to `isModuleInstalled()` succeeds. Importantly, if the success listener is called, that just tells you that the client succeeded in finding out **whether** the module is installed on the device. In the body of your listener, you need to check whether the module is actually installed or not.
- If the module isn't already installed, this snippet installs it by calling the method `launchInstallRequest()`. That method is defined in the snippet in [Install the low light boost
  module](https://developer.android.com/media/camera/lowlight/low-light-boost-gp/use-client#install).

## Install the low light boost module

If the low light boost module isn't already installed on the device, you'll need
to download and install it from Google Play services. This code shows how to do
that:  

### Kotlin

    private suspend fun launchInstallRequest() {
      Log.v(TAG, "Launching install request")

      try {
        // Check if this device can support Google LLB.
        val isDeviceSupported: Boolean = lowLightBoostClient
          .isDeviceSupported(context).await()

        if (isDeviceSupported) {
          Log.d(TAG, "Device is supported")
          // Show download indicator, if needed.

          try {
            val isInstallSuccessful: Boolean = lowLightBoostClient
              .installModule(context,
                            createInstallStatusCallback()
              ).await()

            if (isInstallSuccessful) {
              Log.d(TAG, "Module installed")
              // Hide download indicator, if needed.
              try {
                openCamera()
              } catch (e: CameraAccessException) {
                Log.e(TAG, "Failed to open camera", e)
              }
            } else {
              Log.d(TAG, "Module install failed")
            }
          } catch (e: Exception) {
            Log.e(TAG, "An error occurred installing the module:", e)
          }
        } else {
          Log.d(TAG, "Device is not supported")
        }
      } catch (e: Exception) {
        Log.e(TAG, "An error occurred checking device support:", e)
      }
    }

### Java

    private void launchInstallRequest() {
      Log.v(TAG, "Launching install request");
      // Check if this device can support Google LLB.
      lowLightBoostClient
        .isDeviceSupported(context)
        .addOnSuccessListener(
          (isDeviceSupported) -> {
            if (isDeviceSupported) {
              Log.d(TAG, "Device is supported");
              // Show download indicator, if needed.
              lowLightBoostClient
                .installModule(
                  this,
                  createInstallStatusCallback()
                )
                .addOnSuccessListener(
                  (result) -> {
                    if (result) {
                      Log.d(TAG, "Module installed");
                      // Hide download indicator, if needed.
                      try {
                        openCamera();
                      } catch (CameraAccessException e) {
                        Log.e(TAG, "Failed to open camera", e);
                      }
                    } else {
                      Log.d(TAG, "Module install failed");
                    }
                  }
                );
            } else {
              Log.d(TAG, "Device is not supported");
            }
          })
        .addOnFailureListener(
          (e) -> {
            Log.e(TAG, "Failed to check device support", e);
          });
    }

### Key points about this code

- When you call [`LowLightBoostClient.installModule()`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient#installModule(android.content.Context,com.google.android.gms.cameralowlight.LowLightBoostClient.InstallStatusCallback)) you pass a callback object, which implements [`LowLightBoostClient.InstallStatusCallback`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient.InstallStatusCallback). `installModule()` calls methods in that callback to indicate the status of the download. For example, if the download is paused, `installModule()` calls the callback object's [`onDownloadPause()`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient.InstallStatusCallback#onDownloadPaused()) method.
- In this code snippet, the callback object is created by the `createInstallStatusCallback()` method. You'd need to write that method yourself, along these lines:

### Kotlin

    private fun createInstallStatusCallback(): LowLightBoostClient.InstallStatusCallback =
            object : LowLightBoostClient.InstallStatusCallback() {
        override fun onDownloadPending() {
          Log.d(TAG, "onDownloadPending")
          // Code here...
        }

        override fun onDownloadStart() {
          Log.d(TAG, "onDownloadStart")
          // Code here...
        }

        // other overrides here...
      }

### Java

    private InstallStatusCallback createInstallStatusCallback() {
      new LowLightBoostClient.InstallStatusCallback() {
        @Override
        public void onDownloadPending() {
          Log.d(TAG, "onDownloadPending");
          // Code here...
        }

        @Override
        public void onDownloadStart() {
          Log.d(TAG, "onDownloadStart");
          // Code here...
        }

      // other overrides here...
    }

- [`LowLightBoostClient.isDeviceSupported()`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient#isDeviceSupported(android.content.Context))
  checks whether the Android-powered device and operating system support Google
  Low Light Boost. If not, don't download the module.

- The method
  [`LowLightBoostClient.installModule()`](https://developers.google.com/android/reference/com/google/android/gms/cameralowlight/LowLightBoostClient#installModule(android.content.Context,com.google.android.gms.cameralowlight.LowLightBoostClient.InstallStatusCallback))
  returns a
  [`Task`](https://developers.google.com/android/reference/com/google/android/gms/tasks/Task)
  object. You use this object to set up success and failure listeners.

- When the install finishes, the success listener verifies the install by
  opening the camera. In the snippet, this is done with a call to
  `openCamera()`. You'll need to write that method yourself.