This guide describes the changes necessary to migrate to version 5.0.

## Gradle and Android Gradle Plugin updates

### Upgrade Gradle and Android Gradle Plugin versions

First, upgrade your Gradle and Android Gradle Plugin versions. This upgrade
includes better compatibility with certain SDK dependencies
(including Kotlin 1.9), as well as some critical bug fixes.

This SDK major release requires the following version dependencies for your
Android application project:

- a Gradle version at least v7.5.0 but no higher than v7.6.0.
- an Android Gradle Plugin (AGP) version in the range of v7.4.x.

You can target a higher version of the plugins; however, you might run
into deprecation warnings, or some new features might not work.

To modify the Gradle version, modify the line in your project's
`/gradle/wrapper/gradle-wrapper.properties` file

    distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip

To modify the Android Gradle Plugin version, modify the `build.gradle` file that
contains the `buildscript` block. For example:

```groovy
buildscript {
    repositories {
        google()
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:7.4.1'
    }
}
```

## Java 7 to Java 8 library support migration

### Step 1 - Enable Java 8 library support

[Source](https://developer.android.com/studio/write/java8-support#library-desugaring)

Since the SDK min API level is 23 and the required AGP version is 7.4+, the
configuration is slightly different from the mentioned source documentation.

```groovy
buildscript {

    repositories {
        google()
        mavenCentral()
        jcenter()
        maven {
            url = uri("https://storage.googleapis.com/r8-releases/raw")
        }
    }
    dependencies {
        classpath 'com.android.tools:r8:8.0.46'
        classpath 'com.android.tools.build:gradle:7.4.1'
    }
}

android {
    compileOptions {
        // Flag to enable support for the new language APIs
        coreLibraryDesugaringEnabled true
        // Sets Java compatibility to Java 8
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.3'
}
```

> [!NOTE]
> **Note:** this script not only enables Java 8 library support but also enables Java 8+ libraries desugaring support. Both are required for using the latest Consumer and Driver SDKs.

### Step 2 - Migrate from Proguard or Dexguard to R8

[R8, source](https://developer.android.com/build/shrink-code)

AGP v7.4+ uses R8 as the default shrinking, obfuscation, and optimization tool
for the binary, so no special action is needed at this point.

If the project is migrated from AGP 4.0+, AGP may issue a the following warnings
about file removals:

- `useProguard true` usage in `build.gradle` file
- `android.enableR8=false` usage in `gradle.properties` file

Removing these lines usually resolves those issues.

## Kotlin 1.6 to 1.9 migration

### Step 1 - Migrate to Kotlin Gradle Plugin 1.9.0

[Source](https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-gradle-plugin/1.9.0)

Update the Kotlin Gradle Plugin version in your application top level module
build.gradle file. Make sure to add `org.jetbrains.kotlin:kotlin-gradle-plugin`
in the dependencies from the buildscript block in case it's missing.

```groovy
buildscript {
  dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0"
  }
}
```

You must migrate your application from Kotlin-synthetics in case you're coming
from Kotlin Gradle Plugin 1.6.X or 1.7.X. Refer to the official [migration
guide](https://developer.android.com/topic/libraries/view-binding/migration) for
more information.

### Step 2 - Upgrade kotlin-stdlib to 1.9.0

[Source](https://kotlinlang.org/api/latest/jvm/stdlib/)

Upgrade `kotlin-stblib` to 1.9.0 in your application build.gradle file.

```groovy
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
}
```

Make sure to remove any references to `kotlin-stdlib-jdk7` or
`kotlin-stdlib-jdk8`. Both dependencies have been consolidated into
`kotlin-stdlib` starting in [Kotlin
1.8.0](https://kotlinlang.org/docs/whatsnew18.html).

## StatusListener deprecation

The `StatusListener` interface is now deprecated (to be removed in v6), in favor
of `DriverStatusListener`.

There are mainly 3 changes:

1. Change the `implements` interface from `StatusListener` to `DriverStatusListener`.
2. Add a `Nullable` `cause` parameter to `updateStatus`.
3. Call the `DriverContextBuilder.setDriverStatusListener` instead of the `setStatusListener`.

`DriverStatusListener` shares the same structure as `StatusListener`. The main
difference between them is that `DriverStatusListener.updateStatus()` takes an
extra parameter named `cause`. This provides users insights on the cause of an
update with error status level.

Typically, you would use `cause` to retrieve the error code returned by Fleet
Engine for failed location updates.

The following sample illustrates how to implement `StatusListener`:

```java
class MyStatusListener implements StatusListener {
  /** Called when background status is updated during actions such as location reporting. */
  @Override
  public void updateStatus(
      StatusLevel statusLevel, StatusCode statusCode, String statusMsg) {
    // Implementation
  }
}

// Inject StatusListener into DriverContext.
DriverContextBuilder.setStatusListener(new MyStatusListener());
```

The following shows a sample `DriverStatusListener` implementation:

```java
class MyStatusListener implements DriverStatusListener {
  /** Called when background status is updated during actions such as location reporting. */
  @Override
  public void updateStatus(
      StatusLevel statusLevel, StatusCode statusCode, String statusMsg, @Nullable Throwable cause) {
    // Existing implementation

    if (cause != null && cause instanceof StatusRuntimeException) {
      if (Status.NOT_FOUND.getCode().equals(cause.getStatus().getCode())) {
        // NOT_FOUND gRPC exception thrown by Fleet Engine.
      }
    }
  }
}

DriverContextBuilder.setStatusListener(new MyStatusListener());
```

### Implement `DriverStatusListener` as a functional interface

`DriverStatusListener` supports Java functional interfaces just like its
predecessor. Here is an example of it:

```java
DriverContextBuilder.setDriverStatusListener((statusLevel, statusCode, statusMsg, cause) -> {
  if (cause != null && cause instanceof StatusRuntimeException) {
    if (Status.NOT_FOUND.getCode().equals(cause.getStatus().getCode())) {
      // NOT_FOUND gRPC exception thrown by Fleet Engine.
    }
  }
});
```