> ## Documentation Index
> Fetch the complete documentation index at: https://cloudinary.com/documentation/llms.txt
> Use this file to discover all available pages before exploring further.

# Android image and video upload


Cloudinary provides support for uploading media directly from your mobile application to your Cloudinary product environment, without going through your servers first. This method allows for faster uploading and a better user experience. It also reduces load on your servers and reduces the complexity of your applications.

This page covers common usage patterns for Android image and video upload with Cloudinary.

For details on all available upload functionality, see the [Upload](upload_images) guide, and the [upload](image_upload_api_reference#upload) method of the Upload API Reference.

For security reasons, mobile applications shouldn't contain your Cloudinary product environment credentials. You can use a [signed upload](#signed_upload), but that requires generating an authentication signature on your backend. In most cases, you will probably use [unsigned uploads](#unsigned_upload) that generally provide all the functionality you need for your mobile application, while restricting upload options that require more security.

> **INFO**: :title=Help us improve our SDK

We'd love to hear your thoughts on using our Android SDK. Please take a moment to complete this [short survey](https://forms.gle/8NdZ7g2RhZMkrC9w9). Thanks for your time!

## MediaManager upload method

The upload request is managed by the MediaManager's `upload` method, which accepts the file to upload as its only parameter. The file can be specified as either: the path to the local file, a byte array, a Resource ID, or a URI. 

The upload request is then dispatched to a background queue via the MediaManager's `dispatch` method, optionally with a set of fully [customizable rules and limits](#upload_policy) letting you choose when each upload request should actually run and how. Requests are automatically rescheduled to be retried later if a recoverable error is encountered (e.g. network disconnections, timeouts). The upload results are dispatched asynchronously and global callbacks can be defined, as well as specific callbacks per request. 

The following simple example uploads an image called `imageFile.jpg` using the default signed upload options:

```android
String requestId = MediaManager.get().upload("imageFile.jpg").dispatch();
```

## Unsigned upload

Unsigned upload is an option for performing upload without the need to generate a signature on your backend. Unsigned upload options are controlled by an [upload preset](upload_presets):  to use this feature, you first need to enable unsigned uploading for your Cloudinary product environment from the [Upload Presets](https://console.cloudinary.com/app/settings/upload/presets) page of your Cloudinary Console Settings.

An upload preset is used to define which upload options will be applied to images that are uploaded unsigned with that preset specified. You can edit the preset at any point in time (or create additional upload presets), to define the parameters that will be used for all images that are uploaded unsigned from your mobile application. 

The following simple example uploads an image called `imageFile.jpg` using an upload preset called `sample_preset`:

```android
String requestId = MediaManager.get().upload("imageFile.jpg")
   .unsigned("sample_preset")
   .dispatch();
```

The method returns a `requestId` that can be used to identify the upload request.

## Signed upload

> **INFO**: Signed uploads require a [signature](signatures) which needs to be created using your api_secret. You should never expose your secret in client side code and therefore you need to generate an authentication signature on your backend. Android signed upload with backend support should be implemented in conjunction with one of Cloudinary's backend frameworks (Java, .NET, etc). The various backend frameworks implement helpers to be used in conjunction with iOS, as well as automatically generate the authentication signature for the upload.

To implement signed uploads from an Android device to your Cloudinary product environment you must provide a class that implements the [SignatureProvider](https://github.com/cloudinary/cloudinary_android/blob/524b33f133b2c4c7b05b1664db586405e5c4176b/lib/src/main/java/com/cloudinary/android/signed/SignatureProvider.java) interface. You class must implement a synchronous HTTPS call to your backend signature generation endpoint, which must return an object with a timestamp, your API key, and the [signature](authentication_signatures) itself. 

To enable signed uploads you need to update your call to the MediaManager's `init` method with the name of an instance of your class (`init(Context, SignatureProvider, Map)`). Your class will be implemented whenever an upload must be signed. 

For example:

```android
Map config = new HashMap();
config.put("cloud_name", "myCloudName");
MediaManager.init(this, new SignatureProvider(){
  @Override
  public Signature provideSignature(Map options) {
    // replace the following with a function that calls your backend signature generation endpoint
    SignResult res = signUpload(options);  // example name of a function that implements a synchronous HTTPS call
    return new Signature(res.getSignature(), res.getApiKey(), res.getTimestamp());
  }
  @Override
  public String getName() {
    return "SampleSignatureProvider"; // for logging purposes
  }
}, config);
```

## Upload options

Use the MediaManager's `option` method to add an [upload parameter](image_upload_api_reference#upload) to the upload request. The method accepts 2 parameters: the first specifies the name of the upload parameter and the second its value. For example, to upload an image called `samplepic.jpg` and set the`public_id` option to `sample1`:

```android
String requestId = MediaManager.get().upload("samplepic.jpg")
   .unsigned("sample_preset")
   .option("public_id", "sample1")
   .dispatch();
```

If you want to include more than one upload parameter in the request you can either chain another `option` method for each parameter, or use the MediaManager's `options` method to pass a Map of all parameters. Note that if you use the `options` method it must come before any other method passing upload parameters.

For example, to upload an image called `dog.jpg`, set the public\_id to `my_dog`, and add the tag `animal`:

```android
String requestId = MediaManager.get().upload("dog.jpg")
   .unsigned("preset1")
   .option("public_id", "my_dog")
   .option("tags", "animal")
   .dispatch();
```

Which is equivalent to:

```android
Map<String, Object> options = new HashMap<>();
options.put("public_id", "my_dog");
options.put("tags", "animal");
String requestId = MediaManager.get().upload("dog.jpg")
   .options(options)
   .unsigned("preset1")
   .dispatch();
```
> **NOTE**:
>
> For security reasons, only [this restricted set](image_upload_api_reference#unsigned_upload_parameters) of parameters can be used in an **unsigned** upload request. All other parameters you want to apply must be defined in the upload preset. For more information, see [Unsigned upload parameters](image_upload_api_reference#unsigned_upload_parameters).
> If a supported parameter is included both in the unsigned upload call and in the unsigned upload preset, the upload preset value usually takes precedence, but there are some exceptions. For details, see [Upload preset precedence](upload_presets#upload_preset_precedence).
## Upload response

By default, uploading is performed asynchronously. Once finished, the uploaded image is immediately available for transformation and delivery. 

An upload call returns a JSON object with content similar to the following:

```json
{
    "public_id":"tquyfignx5bxcbsupr6a",
    "asset_id": "55fd6d6f6e6043567",
    "version":1375302801,
    "signature":"52ecf23eeb987b3b5a72fa4ade51b1c7a1426a97",
    "width":1920,
    "height":1200,
    "format":"jpg",
    "resource_type":"image",
    "created_at":"2017-07-31T20:33:21Z",
    "bytes":737633,
    "type":"upload",
    "access_mode": "public",
    "url":
        "https://res.cloudinary.com/demo/image/upload/v1375302801/tquyfignx5bxcbsupr6a.jpg",
    "secure_url":
        "https://res.cloudinary.com/demo/image/upload/v1375302801/tquyfignx5bxcbsupr6a.jpg",
    "etag":"1adf8d2ad3954f6270d69860cb126b24"
}
```

The response includes HTTP and HTTPS URLs for accessing the uploaded media asset as well as additional information regarding the uploaded asset: the public ID, resource type, width and height, file format, file size in bytes, a signature for verifying the response, and more.  

## Chunked upload

The SDK includes the `uploadLarge` method  which offers more tolerance for network issues. This method uploads a large file to the cloud in chunks, and is required for any files that are larger than 100 MB. By default, the chunk size is set to 20 Megabytes but can be set to as low as 5 Megabytes with the `chunkSize` parameter. For example, uploading a large video file called `myVid.mp4` as a raw file and setting the chunk size to 6 Megabytes:

```android
Map response = cloudinary.uploader().uploadLarge("myVid.mp4", ObjectUtils.asMap("resource_type", "raw", "chunk_size", 6291456));
```

## Timeout options

The Android SDK offers 2 extra parameters for overriding the default timeout values when trying to upload a file:

* `connect_timeout` - the maximum amount of time in milliseconds to wait for a connection to be established.
* `read_timeout` - the maximum amount of time in milliseconds to wait for data available for read.

By default, these timeout values vary between different mobile devices. You can override the default timeout values, and give a single value to all devices, by adding these parameters with the `option` method. 

For example, to upload an image and set both timeouts to 10 seconds:

```android
String requestId = MediaManager.get().upload("dog.jpg")
   .unsigned("preset1")
   .option("connect_timeout", 10000)
   .option("read_timeout", 10000)
   .dispatch();
```

## Callbacks

You can track upload progress by getting callbacks on the following events: `onStart`, `onProgress`, `onSuccess`, `onError`, and `onReschedule`. The upload results are dispatched asynchronously, with 2 options for adding callback functionality:

1. [Implement the UploadCallBack interface](#implement_the_uploadcallback_interface) for specific callbacks per request.
2. [Extend the ListenerService](#extend_the_listenerservice) for global callbacks, even when your app has been shut down, or is running in the background.

### Implement the UploadCallBack interface

Create a class that implements the [UploadCallBack](https://github.com/cloudinary/cloudinary_android/blob/8e3b3185961ca093eb3ecf3faaffe5f99e8a8dea/lib/src/main/java/com/cloudinary/android/callback/UploadCallback.java) interface, and add functionality by overriding specific callback events with your own code. Use the MediaManager's `callback` method to add the name of an instance of your class to the upload request. The callback is specific to the current upload request only. The following example includes some example code for the `onProgress` event:

```android
String requestId = MediaManager.get().upload(filePath).callback(new UploadCallback() {
  @Override
  public void onStart(String requestId) {
    // your code here
  }
  @Override
  public void onProgress(String requestId, long bytes, long totalBytes) {
            // example code starts here
    Double progress = (double) bytes/totalBytes;
    // post progress to app UI (e.g. progress bar, notification)
            // example code ends here                   
  }
  @Override
  public void onSuccess(String requestId, Map resultData) {
     // your code here
  }
  @Override
  public void onError(String requestId, ErrorInfo error) {
     // your code here
  }
  @Override
  public void onReschedule(String requestId, ErrorInfo error) {
    // your code here
  }})
  .dispatch();
```

### Extend the ListenerService

Extend the [ListnerService](https://github.com/cloudinary/cloudinary_android/blob/8e3b3185961ca093eb3ecf3faaffe5f99e8a8dea/lib/src/main/java/com/cloudinary/android/callback/ListenerService.java) service, and add functionality by overriding specific callback events with your own code. Callback events for all upload requests will be routed to your service, even when your app has been shut down, or is running in the background.

The following example includes some example code extending the ListenerService :

```android
public class UploadListener extends ListenerService {
    @Override
    public void onStart(String requestId) {
        // your code here
    }
    @Override
    public void onProgress(String requestId, long bytes, long totalBytes) {
        // example code starts here
        Double progress = (double) bytes/totalBytes;
        // post progress to app UI (e.g. progress bar, notification)
        // example code ends here
    }
    @Override
    public void onSuccess(String requestId, Map resultData) {
        // your code here
    }
    @Override
    public void onError(String requestId, ErrorInfo error) {
        // your code here
    }
    @Override
    public void onReschedule(String requestId, ErrorInfo error) {
        // your code here
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

```

Make sure to register your class in the manifest, with both a `service` tag and a cloudinaryCallbackService `meta-data` tag, both within the `application` tag.

For example, if your class is called `UploadListner`:

```android
<application
  ...
  <service 
    android:name="com.myapp.UploadListner" />
  <meta-data
    android:name="cloudinaryCallbackService"
    android:value="com.myapp.UploadListner" />
  ...
</application>
```

## Preprocess uploads

Use the `preprocess` method to make changes to an image before initiating the upload request. 

### Preprocess image uploads

Image preprocessing is defined by an object of type `ImageProcessChain` that loads the image with a `BitmapDecoder` using the specified size, runs predefined processing steps, and then saves the image with a `BitmapEncoder` using the specified format and quality. The following types of processing steps are currently available: 

Step Type | Parameter | Description
---|---|----
Limit | (width, height) | Scales down the image to fit within a bounding box of the given dimensions.  
DimensionsValidator | (min\_width, max\_width, min\_height, max\_height) |  Verifies the minimum and maximum dimensions for the image. Throws an error if the image does not fit within these dimensions.
Crop | (point, point) | Crops the image as defined by two points that reference the corners of the desired rectangle (any two points that create a diagonal within the image is a valid crop).
BitmapEncoder | (format, quality) | Saves the image using the given format (JPEG, PNG or WEBP) and quality. 

> **INFO**: If you include preprocessing in your upload request, you also need to pass an Android `context` instance when calling the `dispatch` method.

Examples:

1. To limit an image to a size of 1000x1000 pixels, make sure that the image is at least 10x10 pixels in size and change the format to WEBP with a quality of 80:

    ```android
    String requestId = MediaManager.get().upload(imageFile)
      .unsigned("sample_app_preset")
      .preprocess(new ImagePreprocessChain()
        .loadWith(new BitmapDecoder(1000, 1000))
        .addStep(new Limit(1000, 1000))
        .addStep(new DimensionsValidator(10,10,1000,1000))
        .saveWith(new BitmapEncoder(BitmapEncoder.Format.WEBP, 80)))
      .dispatch(context);
    ```

    The `limitDimensionsChain` shortcut method can be used instead of loading the decoder and adding the limit step separately. For example, the following code accomplishes the same as the example code above:

    ```android
    String requestId = MediaManager.get().upload(imageFile)
      .unsigned("sample_app_preset")
      .preprocess(ImagePreprocessChain.limitDimensionsChain(1000, 1000)
        .addStep(new DimensionsValidator(10,10,1000,1000))
        .saveWith(new BitmapEncoder(BitmapEncoder.Format.WEBP, 80)))
      .dispatch(context);
    ```

2. To crop the image to a rectangle given by the points 250,250 and 750,750:

    ```android
    String requestId = MediaManager.get().upload(imageFile)
      .unsigned("sample_app_preset")
      .preprocess(new ImagePreprocessChain()
        .loadWith(new BitmapDecoder(1000, 1000))
        .addStep(new Crop(new Point(250, 250), new Point(750, 750))))
      .dispatch(context);
    ```

> **NOTE**: In the case that you need to create your own preprocessing step you can implement the `Preprocess` interface with your own custom code and then declare it as an additional `addStep`.

### Preprocess video uploads

Video preprocessing is defined by an object of type `VideoProcessChain` for preprocessing a video. The following types of processing steps are currently available: 

Step Type | Parameter | Description
---|---|----
Transcode | (FrameRate, Width, Height, KeyFramesInterval, TargetAudioBitrateKbps, and TargetVideoBitrateKbps) | Transcodes a video according to the given parameters.

> **INFO**: If you include preprocessing in your upload request, you also need to pass an Android `context` instance when calling the `dispatch` method.

For example, to transcode a video to a frame rate of 30 frames/sec, a size of 1280x720 pixels, a keyframe interval of 3 seconds, an audio bitrate of 128 Kbps, and a video bitrate of 3 Mbps: 

```android
Parameters parameters = new Parameters();
parameters.setFrameRate(30);
parameters.setWidth(1280);
parameters.setHeight(720);
parameters.setKeyFramesInterval(3);
parameters.setTargetAudioBitrateKbps(128);
parameters.setTargetVideoBitrateKbps((int) (3 * 1024 * 1024));

MediaManager.get().upload(videoFile)
    .unsigned("sample_video_preset")
    .preprocess(new VideoPreprocessChain()
    .addStep(new Transcode(parameters)))
  .dispatch(context);
```

> **NOTE**: In the case that you need to create your own preprocessing step you can implement the `Preprocess` interface with your own custom code and then declare it as an additional `addStep`.

## Upload policy

Use the `policy` method to configure the MediaManager's upload request to run under specific circumstances. The policy is defined by an object of type `UploadPolicy` that has the following properties: 

Property | Type | Description
---|---|----
networkPolicy | NetworkType | Limit the upload to a specific type of network connectionPossible values:-UploadPolicy.NetworkType.NONE -UploadPolicy.NetworkType.ANY(`default`) -UploadPolicy.NetworkType.UNMETERED
requiresCharging | boolean | Upload only when the mobile device is currently charging. Default: `false`
requiresIdle | boolean | Upload only when the mobile device is currently idle. Default: `false`
maxRetries | int | The maximum number of times to retry the upload. Default: `5`
backoffCriteria |backoffMillis, backoffPolicy| The backoff policy to implement before retrying.
&nbsp;&nbsp;&nbsp;&nbsp;backoffMillis | long |   The time to wait in milliseconds before retrying. Default: `120000` (2 minutes)
&nbsp;&nbsp;&nbsp;&nbsp;backoffPolicy | BackoffPolicy  |   Whether the time between successive upload attempts increases linearly (2, 4, 6, 8, etc) or exponentially (2, 4, 8, 16, etc)   Possible values:-UploadPolicy.BackoffPolicy.LINEAR-UploadPolicy.BackoffPolicy.EXPONENTIAL (default)

For example, to request that a specific upload runs only on an unmetered network (e.g. wifi), with a maximum of 7 retries, and waits 5 minutes before retrying with a linear backoff policy:

```android
String requestId = MediaManager.get().upload(imageFile)
   .unsigned("sample_app_preset")
   .policy(new UploadPolicy.Builder()
      .maxRetries(7)
      .backoffCriteria(300000, UploadPolicy.BackoffPolicy.LINEAR)
      .networkPolicy(UploadPolicy.NetworkType.UNMETERED)
      .build())
   .dispatch();
```

## Immediate upload

If you need to start an upload immediately with no delay, you can use the `startNow` method to bypass the managed upload process controlled by the [policy](#upload_policy) method. The `startNow` method replaces the `dispatch` method, and you will also need to pass an Android `context` instance when calling the method.

For example, to start an upload immediately:

```android
String requestId = MediaManager.get().upload("imageFile.jpg")
    .unsigned("sample_app_preset")
    .startNow(context);
```

> **INFO**:
>
> Take note of the following considerations before using the `startNow` method:

> * The upload will run on a background thread instead of the device's background jobs infrastructure.

> * The `policy` method is ignored and the upload will not benefit from automatic retries and smart scheduling - a failure is a failure.

> * The upload will not count against the total running jobs and will ignore the maximum allowed jobs - 'start now' ignores every other limitation.

## Cancel an upload

If you need to cancel an upload in progress, you can use either the `cancelRequest` method and pass the ID of the request to cancel, or use the `cancelAllRequests` method to cancel all requests and jobs in progress.

To cancel a single request:

```android
boolean canceled = MediaManager.get().cancelRequest(requestId);
// returns True if successful
```

To cancel all requests:

```android
int totalCanceled = MediaManager.get().cancelAllRequests();
// returns the number of canceled requests
```

## Global policy

To override the default policy for all upload requests, use the `setGlobalUploadPolicy` method of the MediaManager class. Call the method before using any other methods of the MediaManager class, preferably in `Application.onCreate()`. The global policy is defined by an object of type `GlobalUploadPolicy`, which inherits the same properties as the `UploadPolicy` object described above, with one additional property:

Property | Type | Description
---|---|----
maxConcurrentRequests | int | The maximum number of upload requests that can run concurrently. Default: `5`

For example, to set the default for upload requests to run only on an unmetered network (e.g. wifi), with no more than 3 upload requests to run concurrently:

```android
MediaManager.get().setGlobalUploadPolicy(
   new GlobalUploadPolicy.Builder()
      .maxConcurrentRequests(3)
      .networkPolicy(UploadPolicy.NetworkType.UNMETERED)
   .build());
```

## Android upload widget

The Android upload widget offers an interactive user interface that enables your users to edit and then upload files to your Cloudinary product environment. The widget, requiring just a couple lines of code to integrate, eliminates the need to develop certain in-house interactive media upload capabilities. Currently, the widget provides an interactive cropping capability and allows rotation of an image before uploading.

You call the upload widget using the `startActivity` method of the UploadWidget, passing an Android Activity for context (if the method is called from within an activity, `this` is a valid context), and a request code of your choice.

```android
void showWidget(){
    UploadWidget.startActivity(activity, UPLOAD_WIDGET_REQUEST_CODE);
}
```

This will automatically launch the default file picker, allow the user to crop/rotate their images as desired, and also upload the images to Cloudinary via the dispatch queue.

### Android upload widget options

If you wish to customize the behavior of the widget, you can add an `options` object to the method that determines how the images are uploaded. The `options` object supports 2 parameters as follows:

* An **action** specifying how to upload the files, either via the upload queue (DISPATCH), or immediately (START_NOW). You can also specify NONE if you want to [intercept](#intercepting_the_edited_images) the results before uploading.
* A **list of URIs** (android resource points), which is typically returned from the default Android file picker or the camera API, or `null` to let the widget launch the default file picker to select the files to upload. 

For example, to call the upload widget with a list of URIs, and dispatch the upload via the queue:

```android
UploadWidget.startActivity(activity, UPLOAD_WIDGET_REQUEST_CODE,
       new UploadWidget.Options(UploadWidget.Action.DISPATCH, uris));
```

The following example shows how to call the widget with the default file picker, and then upload the files immediately:

```android
UploadWidget.startActivity(activity, UPLOAD_WIDGET_REQUEST_CODE,
       new UploadWidget.Options(UploadWidget.Action.START_NOW, null));
```

### Intercepting the edited images

If you specify NONE as action for the upload widget [options](#android_upload_widget_options), you can intercept the results (edited images) from the upload widget by adding code within the calling Activity and overriding the `onActivityResult` method. Using a static helper method, each result can be directly transformed into an UploadRequest and then customized, if necessary, and dispatched. All the requested edits made by the user, including rotation and cropping, will be automatically added to the request, as preprocessing steps, before uploading to Cloudinary.

For example:

```android
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        if (requestCode == UPLOAD_WIDGET_REQUEST_CODE) {
            List<UploadWidget.Result> results = data.getParcelableArrayListExtra(UploadWidget.RESULT_EXTRA);
            for (UploadWidget.Result result: results) {
                UploadRequest request = UploadWidget.preprocessResult(this, result); 
      // customize the request as necessary - add options, set upload policy, etc.            
                ...    
      // dispatch the request. 
                request.dispatch(this);
            }
      // If the widget was launched using DISPATCH or START_NOW, no further 
      // code is needed. In fact the entire onActivityResult Callback is not necessary. 
      // If handles to the in-progress upload are needed (for instance to track progress 
      // or cancel requests), those are available as part of the result set:
           for (UploadWidget.Result result : results) {
               // note: this field will only be populated when using DISPATCH or START_NOW:
               String requestId = result.requestId;
               ...
           }
        } else if (requestCode == ...
    }
}
```
