This document covers the steps you need to take to migrate your projects from
Google Mobile Vision (GMV) to ML Kit on Android.

## Overall API Changes

These changes apply to all APIs:

- GMV APIs return a `SparseArray<T>` result synchronously. ML Kit APIs use the Google Play services Task API to return results asynchronously.
- GMV uses the `isOperational()` call in the API surface to indicate whether a module has been downloaded successfully and is ready to use. ML Kit has no such method. ML Kit throws an `MlKitException.UNAVAILABLE` exception if a module hasn't been downloaded. You can catch this exception and process the next frame or set a timeout and retry with the current frame.
- GMV methods use [`Frame`](https://developers.google.com/android/reference/com/google/android/gms/vision/Frame.md.txt) for input. ML Kit uses [`InputImage`](https://developers.google.com/android/reference/com/google/mlkit/vision/common/InputImage.md.txt).
- GMV provides `MultiDetector`, `MultiProcessor` and `FocusingProcessor` frameworks for performing multiple detections and results filtering. ML Kit does not provide such mechanisms, but the same functionality can be implemented by the developer if desired.

## Update Gradle Imports

Update the dependencies for the ML Kit Android libraries in your module (app-level) Gradle file, which is usually `app/build.gradle`, according to the following table:

| API | GMV Artifact | ML Kit Artifact |
|---|---|---|
| FaceDetector | `com.google.android.gms:play-services-vision:x.x.x` | `com.google.android.gms:play-services-mlkit-face-detection:17.1.0` |
| BarcodeDetector | `com.google.android.gms:play-services-vision:x.x.x` | `com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1` |
| TextRecognition | `com.google.android.gms:play-services-vision:x.x.x` | `com.google.android.gms:play-services-mlkit-text-recognition:19.0.2` |
| CameraSource | `com.google.android.gms:play-services-vision:x.x.x` | `com.google.mlkit:camera:16.0.0-beta3` |

## API Changes

This section describes corresponding GMV and ML Kit classes and methods for each Vision API, and shows how to initialize the API.

### FaceDetector

Recode the initialization as shown in this example:

### GMV

```java
detector = new FaceDetector.Builder(context)
    .setMode(FaceDetector.ACCURATE_MODE)
    .setLandmarkType(FaceDetector.ALL_LANDMARKS)
    .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
    .build();
```

### ML Kit

```java
FaceDetectorOptions options = new FaceDetectorOptions.Builder()
    .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
    .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
    .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
    .build();

detector = FaceDetection.getClient(options);
```

Change the following class and method names:

| `android.gms.vision.face` | `mlkit.vision.face` |
|---|---|
| `FaceDetector` | `FaceDetector` |
| `SparseArray<Face> detect(Frame frame)` | `Task<List<Face>> process(@NonNull InputImage image)` |
| `FaceDetector.Builder.setClassificationType(int classificationType)` | `FaceDetectorOptions.Builder.setClassificationMode(int classificationMode)` |
| `NO_CLASSIFICATIONS, ALL_CLASSIFICATIONS ` | `CLASSIFICATION_MODE_NONE, CLASSIFICATION_MODE_ALL ` |
| `FaceDetector.Builder.setLandmarkType(int landmarkType)` | `FaceDetectorOptions.Builder.setLandmarkMode(int landmarkMode)` |
| `NO_LANDMARKS, ALL_LANDMARKS, CONTOUR_LANDMARKS` | `LANDMARK_MODE_NONE, LANDMARK_MODE_ALL` use `#setContourMode` to replace GMV CONTOUR_LANDMARKS) |
| `FaceDetector.Builder.setTrackingEnabled(boolean trackingEnabled)` | `FaceDetectorOptions.Builder.enableTracking()` |
| `FaceDetector.Builder.setMinFaceSize(float proportionalMinFaceSize)` | `FaceDetectorOptions.Builder.setMinFaceSize(float minFaceSize)` |
| `FaceDetector.Builder.setMode(int mode)` | `FaceDetectorOptions.Builder.setPerformanceMode(int performanceMode)` |
| `FAST_MODE, ACCURATE_MODE` | `PERFORMANCE_MODE_FAST, PERFORMANCE_MODE_ACCURATE` |
| `FaceDetector.Builder.setProminentFaceOnly(boolean prominentFaceOnly)` | This feature is covered by face contour mode. |
| `Face` | `Face` |
| `Contour` | `FaceContour ` |
| `Landmark` | `FaceLandmark` |
| `Face.getContours()` | `Face.getAllContours()` |
| `Face.getEulerY()` | `Face.getHeadEulerAngleY()` |
| `Face.getEulerZ()` | `Face.getHeadEulerAngleZ()` |
| `Face.getId()` | `Face.getTrackingId()` |
| `Face.getIsLeftEyeOpenProbability()` | `Face.getLeftEyeOpenProbability()` |
| `Face.getIsRightEyeOpenProbability()` | `Face.getRightEyeOpenProbability()` |
| `Face.getIsSmilingProbability()` | `Face.getSmilingProbability()` |
| `Face.getLandmarks()` | `Face.getLandmark(int landmarkType)` |
| `Face.getPosition() Face.getHeight() Face.getWidth()` | `Face.getBoundingBox()` |

### BarcodeDetector

Recode the initialization as shown in this example:

### GMV

```java
barcodeDetector = new BarcodeDetector.Builder(context).build());
```

### ML Kit

```java
barcodeScanner = BarcodeScanning.getClient();
```

Change the following class and method names:

| `android.gms.vision.barcode` | `mlkit.vision.barcode` |
|---|---|
| `BarcodeDetector` | `BarcodeScanner` |
| `SparseArray<Barcode> detect(Frame frame)` | `Task<List<Barcode>> process(@NonNull InputImage image)` |
| `Barcode` | `Barcode` |

### TextRecognition

Recode the initialization as shown in this example:

### GMV

```java
textRecognizer = new TextRecognizer.Builder(context).build();
```

### ML Kit

```java
textRecognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);
```

Change the following class and method names:

| `android.gms.vision.text` | `mlkit.vision.text` |
|---|---|
| `TextRecognizer` | `TextRecognizer` |
| `SparseArray<TextBlock> detect(Frame frame)` | `Task<Text> process(@NonNull InputImage image)` |
| `SparseArray<TextBlock>` | `Text` |
| `Line` | `Line` |
| `TextBlock` | `TextBlock` |
| `Element` | `Element` |
| `getLanguage()` | `getRecognizedLanguage()` |
| `getBoundingBox()` | `getBoundingBox()` |
| `getCornerPoints()` | `getCornerPoints()` |
| `TextBlock.getComponents()` | `TextBlock.getLines()` |
| `TextBlock.getValue()` | `TextBlock.getText()` |
| `Element.getValue()` | `Element.getText()` |

### CameraSource

If you use the CameraSource library provided by Google Mobile Vision, you can
easily migrate to ML Kit's [`CameraXSource`](https://developers.google.com/android/reference/com/google/mlkit/vision/camera/CameraXSource.md.txt)
library, provided your app is running on a min sdk version \>= 21.

Change the following class and method names:

| `android.gms.vision` | `mlkit.vision.camera` |
|---|---|
| `CameraSource` | `CameraSourceConfig` |
| `CameraSource.Builder` | `CameraSourceConfig.Builder` |
| `CameraSource.Builder.setAutoFocusEnabled` | Autofocus is provided by default when using CameraX. |
| `CameraSource.Builder.setFacing` | `CameraSourceConfig.Builder.setCameraFacing` |
| `CameraSource.Builder.setFocusMode` | Autofocus is provided by default when using CameraX. |
| `CameraSource.Builder.setRequestedFps` | Deprecated. |
| `CameraSource.Builder.setRequestedPreviewSize` | `CameraSourceConfig.Builder.setRequestedPreviewSize` |
| `CameraSource` | `CameraXSource` |
| `new CameraSource.Builder(mContext, detector)....build();` | `CameraXSource(CameraSourceConfig, PreviewView)` |
| `getCameraFacing()` | `getCameraFacing()` |
| `getPreviewSize()` | `getPreviewSize()` |
| `release()` | `close()` |
| `start(SurfaceHolder surfaceHolder)` | `start() // The previewview is set in the CameraSourceConfig` |
| `start()` | `start()` |
| `stop()` | `stop()` |
| `Detector.Processor` | `DetectionTaskCallback` |
| `receiveDetections(Detections<T> detections)` | `void onDetectionTaskReceived(@NonNull Task<ResultT> detectionTask);` |
| `release()` | Handled internally |
| `CameraSource.PictureCallback` | Deprecated |
| `CameraSource.ShutterCallback` | Deprecated |

## Getting help

If you run into any issues, check out our [Community page](https://developers.google.com/ml-kit/community)
where we outline the channels available for getting in touch with us.