diff --git a/.cursor/rules/cloudinary.mdc b/.cursor/rules/cloudinary.mdc
new file mode 100644
index 0000000..17cd505
--- /dev/null
+++ b/.cursor/rules/cloudinary.mdc
@@ -0,0 +1,8 @@
+---
+description: Cloudinary cloudinary_android — agent guide
+alwaysApply: true
+---
+
+Read and follow `AGENTS.md` in the repository root. It is the single
+authoritative guide for this package: build/test commands, conventions,
+gotchas, and when to use this SDK versus a sibling Cloudinary package.
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..bded2b6
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,5 @@
+# Cloudinary cloudinary_android — instructions for AI coding agents
+
+Read `AGENTS.md` in the repository root and follow it. It is the single
+authoritative guide for this package: build/test commands, conventions,
+gotchas, and when to use this SDK versus a sibling Cloudinary package.
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..6485d31
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,74 @@
+# AGENTS.md — cloudinary_android
+
+## What this package is (one line)
+Native Android client SDK (Java/Kotlin) for Cloudinary: on-device media upload via a background, retrying upload queue, plus in-app transformation and delivery URL building. Current release **3.1.2** (minSdk 21, compileSdk 34).
+
+## When to use this / when NOT to use this
+- **Use this when:** you are in a native Android app (Java or Kotlin) and need to upload from the device (files, `Uri`, camera captures) through a background queue with retries and network policies, or build delivery/transformation URLs in-app with `MediaManager.get().url()`.
+- **Do NOT use this when:** you are building a **cross-platform React Native app** (use [cloudinary-react-native](https://github.com/cloudinary/cloudinary-react-native)) or doing **server-side JVM work** — signed uploads, the Admin API, signature generation (use [cloudinary_java](https://github.com/cloudinary/cloudinary_java); that is also where the server-side signature this SDK consumes is generated).
+- **Sibling packages:** `cloudinary_java` = server-side JVM SDK + signature generation; `cloudinary-react-native` = cross-platform mobile; [android-demo](https://github.com/cloudinary/android-demo) = full sample app to copy from. Rule of thumb: runs **on the device** → this SDK; holds the `api_secret` → server only, use `cloudinary_java`.
+
+## Repo layout (multi-module Gradle)
+Modules (from `settings.gradle`): `:core` (URL building + upload engine), `:preprocess`, `:ui`, `:glide-integration`, `:download`, `:all` (aggregate), `:sample` (demo app). Public entry point for app code is `MediaManager`.
+
+## Setup
+Add the dependency to your app `build.gradle`:
+```gradle
+implementation 'com.cloudinary:cloudinary-android:3.1.2'
+```
+Configuration / credentials — only `cloud_name` is needed (no `api_key`/`api_secret`). Either set it programmatically in `MediaManager.init`, or via `AndroidManifest.xml` meta-data:
+```xml
+
+```
+
+## Minimal runnable example
+```java
+// In your Application.onCreate():
+Map config = new HashMap<>();
+config.put("cloud_name", "myCloudName");
+MediaManager.init(this, config);
+
+// Build a delivery URL anywhere in the app:
+String url = MediaManager.get().url()
+ .transformation(new Transformation().width(100).height(150).crop("fill"))
+ .generate("sample.jpg");
+
+// Queue an unsigned upload (background queue, auto-retry).
+// upload() takes a file-path String, Uri, byte[], or raw-resource int — no File overload.
+String requestId = MediaManager.get().upload(imageFile.getAbsolutePath())
+ .unsigned("sample_preset")
+ .callback(callback) // any UploadCallback impl
+ .dispatch();
+```
+
+## Build / test commands (run these after editing)
+Requires **JDK 17** (per CI). Use the Gradle wrapper (`./gradlew`, `gradlew.bat` on Windows).
+```bash
+./gradlew assemble # build all modules
+./gradlew :core:assemble # build a single module
+```
+Tests are **instrumented** (`androidTest`) and run on a device/emulator — CI runs `connectedCheck`, not plain `test`:
+```bash
+./gradlew clean connectedCheck --stacktrace # the exact command CI runs
+```
+`connectedCheck` requires a running emulator or attached device **and** a configured account: CI exports `CLOUDINARY_URL` before running (`export CLOUDINARY_URL=$(bash tools/get_test_cloud.sh)`). Set `CLOUDINARY_URL` (`cloudinary://:@`) in your environment before running tests locally. CI does not wire a lint task — the stock `./gradlew lint` exists but is not part of the project's checks.
+
+## Conventions & gotchas
+- **`MediaManager.init()` must be called before any other SDK call** — do it in `Application.onCreate()`, not per-Activity.
+- **Never ship the `api_secret` in the app.** Uploads are either unsigned (upload presets) or signed by your server via a `SignatureProvider` passed to `MediaManager.init`. This SDK has no Admin API and cannot sign locally.
+- All uploads are **asynchronous** — `dispatch()` returns a `requestId`; results arrive through `UploadCallback`. Use `UploadPolicy` / `TimeWindow` to constrain retries, network type, and run window.
+- **minSdk 21**, compileSdk 34 (verified in `core/build.gradle`). 3.x targets Android SDK 21 and up; do not drop below.
+- Multi-module: change code in the owning module (`:core` for URL/upload logic) and rebuild that module.
+
+## Canonical docs (leave the repo for depth)
+- Android SDK guide: https://cloudinary.com/documentation/android_integration
+- Upload (presets, callbacks, policy): https://cloudinary.com/documentation/android_image_and_video_upload
+- Image / video transformation: https://cloudinary.com/documentation/android_image_manipulation
+- MCP server (agent/no-code path): https://github.com/cloudinary/mcp-servers
+
+## Agent / MCP note
+If a capability is also exposed via the Cloudinary MCP servers, prefer the MCP tool for autonomous task execution and use this SDK for code generation inside an Android app. See cloudinary/mcp-servers.
+
+## Commit / PR conventions
+- Open issues/PRs against https://github.com/cloudinary/cloudinary_android. See `CONTRIBUTING.md`.
+- CI (`.github/workflows/android-build.yml`) runs `./gradlew clean connectedCheck` on push and PR — ensure instrumented tests pass on an emulator before opening a PR. The repo documents no commit-message convention, so match the existing history.
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..3b38abd
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,35 @@
+@AGENTS.md
+
+# CLAUDE.md — cloudinary_android
+
+## What this repo is
+
+Native Android client SDK (Java/Kotlin) for Cloudinary: on-device media upload via a background, retrying queue, plus in-app transformation and delivery URL building via `MediaManager`. Current release: **3.1.2** (minSdk 21, compileSdk 34).
+
+## Key constraints / gotchas
+
+- **`MediaManager.init()` must be called exactly once in `Application.onCreate()`** — not per-Activity. Calling it twice throws `IllegalStateException: MediaManager is already initialized`.
+- **Never ship `api_secret` in the app.** Uploads use unsigned upload presets or a `SignatureProvider` that calls your server. This SDK has no Admin API and cannot sign locally.
+- `upload()` accepts a file-path `String`, `Uri`, `byte[]`, or raw-resource `int` — **there is no `File` overload**. Use `imageFile.getAbsolutePath()` for files.
+- `dispatch()` is async — returns a `requestId` immediately; results arrive through `UploadCallback` (`onStart`, `onProgress`, `onSuccess`, `onError`, `onReschedule`).
+- Multi-module Gradle project: `:core` (URL building + upload engine), `:preprocess`, `:ui`, `:glide-integration`, `:download`, `:all` (aggregate), `:sample`. Public entry point is `MediaManager`.
+- `CLOUDINARY_URL` for tests: `cloudinary://:@`. In the manifest, only the cloud name goes in — `cloudinary://@` (no secret).
+- CI does not wire a lint task — `./gradlew lint` exists but is not part of the project's checks.
+
+## Verified build / test commands
+
+Requires **JDK 17** (per CI). Use the Gradle wrapper (`./gradlew` on Linux/macOS, `gradlew.bat` on Windows).
+
+```bash
+./gradlew assemble # build all modules
+./gradlew :core:assemble # build a single module
+```
+
+Tests are **instrumented** (`androidTest`) and require a running emulator or attached device:
+
+```bash
+export CLOUDINARY_URL=cloudinary://:@
+./gradlew clean connectedCheck --stacktrace
+```
+
+CI runs `./gradlew clean connectedCheck` and exports `CLOUDINARY_URL` via `tools/get_test_cloud.sh` before the run. Plain `./gradlew test` does not run the instrumented suite.
diff --git a/README.md b/README.md
index 36d4a07..345618f 100644
--- a/README.md
+++ b/README.md
@@ -1,203 +1,148 @@
-Cloudinary Android SDK
-======================
-[](https://app.travis-ci.com/github/cloudinary/cloudinary_android)
-
-## About
-The Cloudinary Android SDK allows you to quickly and easily integrate your application with Cloudinary.
-Effortlessly optimize and transform your cloud's assets.
-
-### Additional documentation
-This Readme provides basic installation and usage information.
-For the complete documentation, see the [Android SDK Guide](https://cloudinary.com/documentation/android_integration).
-
-## Table of Contents
-- [Key Features](#Key-Features)
-- [Compatibility](#Version-Support)
-- [Installation](#Installation)
-- [Usage](#Usage)
- - [Setup](#Setup)
- - [Transform and Optimize Assets](#Transforming-and-Optimizing-Assets)
- - [Uploading Asset](#Uploading-Assets)
-
-## Key Features
-* [Image Transformation](https://cloudinary.com/documentation/android_image_manipulation)
-* [Video Transformation](https://cloudinary.com/documentation/android_video_manipulation)
-* [Direct File Upload](https://cloudinary.com/documentation/android_image_and_video_upload)
-* [Preprocess](https://cloudinary.com/documentation/android_image_and_video_upload#preprocess_uploads)
-* [Callbacks](https://cloudinary.com/documentation/android_image_and_video_upload#callbacks)
-* [Upload Policy](https://cloudinary.com/documentation/android_image_and_video_upload#upload_policy)
-* [Error Handling](https://cloudinary.com/documentation/advanced_url_delivery_options#error_handling)
-
-## Version Support
-| Cloudinary SDK | Android SDK |
-|----------------|-------------|
-| 3.x | > 21 |
-| 2.x | > 19 |
-| 1.x | > 14 |
+# Cloudinary Android SDK
+[](https://central.sonatype.com/artifact/com.cloudinary/cloudinary-android)
+[](./LICENSE)
+[](https://github.com/cloudinary/cloudinary_android/actions/workflows/android-build.yml)
-## Installation
-
-### Gradle Integration
-Add the following dependency to your build.gradle:
-
-`implementation 'com.cloudinary:cloudinary-android:3.1.2'`
-### Other Options ######################################################################
-The cloudinary_android library is available in [Maven Central](http://repo1.maven.org/maven/). To use it, add the following dependency to your pom.xml:
-
-
- com.cloudinary
- cloudinary-android
- 3.1.2
-
-
-Download the latest cloudinary-android from [here](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-android-core) and the latest cloudinary-core from [here](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core) and put them in your libs folder.
-
-
-## Usage
-
-### Setup
-
-Each request for building a URL of a remote cloud resource must have the `cloud_name` parameter set.
-You can set the `cloud_name` parameter either when initializing the library, or by using the CLOUDINARY_URL meta-data property in `AndroidManifest.xml`.
-
-The entry point of the library is the `MediaManager` object. `MediaManager.init()` must be called before using the library, preferably in `Application.onCreate()`.
-Here's an example of setting the configuration parameters programmatically in your `Applicaion.onCreate(`:
-
- Map config = new HashMap();
- config.put("cloud_name", "myCloudName");
- MediaManager.init(this, config);
-
-Alternatively, you can use the meta-data property. In that case, no configuration is required:
-
- MediaManager.init(this);
-
-Only the cloud_name should be included. Your API key and secret aren't necessary.
-Note: Your API secret should never be exposed in the application.
-
-
- ...
-
- ...
-
-
-
-
-### Transforming and Optimizing Assets
-
-Any image uploaded to Cloudinary can be transformed and embedded using powerful view helper methods:
-
-The following example generates the url for accessing an uploaded `sample` image while transforming it to fill a 100x150 rectangle:
-
- MediaManager.get().url().transformation(new Transformation().width(100).height(150).crop("fill")).generate("sample.jpg")
-
-Another example, embedding a smaller version of an uploaded image while generating a 90x90 face detection based thumbnail:
-
- MediaManager.get().url().transformation(new Transformation().width(90).height(90).crop("thumb").gravity("face")).generate("woman.jpg")
-
-If your application is written in Kotlin you can use the syntax below:
+The `com.cloudinary:cloudinary-android` package is the native Android client SDK for Cloudinary (Java and Kotlin). Use it inside an installed app to upload media from the device through a background, retrying queue and to build transformation and delivery URLs in-app. The current release (3.1.2) targets Android minSdk 21 and compileSdk 34, and depends on `cloudinary-core` (Java) under the hood.
- MediaManager.get().url().transformation(Transformation>().width(90).height(90).crop("thumb").gravity("face")).generate("woman.jpg")
-
-You can provide either a Facebook name or a numeric ID of a Facebook profile or a fan page.
-
-Embedding a Facebook profile to match your graphic design is very simple:
-
- MediaManager.get().url().type("facebook").transformation(new Transformation().width(130).height(130).crop("fill").gravity("north_west")).generate("billclinton.jpg")
-
-### Uploading Assets
-
-The entry point for upload operations is the `MediaManager.get().upload()` call. All upload operations are dispatched to a background queue, with
-a set of fully customizable rules and limits letting you choose when each upload request should actually run. 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 using `UploadCallback`. Global callbacks can be defined, as well as specific callbacks per request.
-Note: In order to receive global callbacks even when the app is already shut down, or in the background, the `ListenerService` class can be extended and registered in the manifest (see the class for further instructions).
-
-The following examples uploads a `File` using the default settings, a request upload callback, and an upload preset (more about upload presets below):
-
- String requestId = MediaManager.get().upload(imageFile).unsigned("sample_preset").callback(callback).dispatch();
-
-The returned `requestId` is used to identify the request in global callbacks and to cancel the request if needed. The callback should be any implementation of `UploadCallback`.
-
-The uploaded image is assigned a randomly generated public Id. As soon as `onSuccess` is called, the image is immediately available for download through a CDN:
-
- MediaManager.get().url().generate("abcfrmo8zul1mafopawefg.jpg")
-
- http://res.cloudinary.com/demo/image/upload/abcfrmo8zul1mafopawefg.jpg
-
-You can also specify your own public ID:
-
- String requestId = MediaManager.get().upload(uri).unsigned("sample_preset").option("public_id", "sample_remote").dispatch();
-
-Using `RequestUploadPolicy`, an upload request can be configured to run under specific circumstance, or within a chosen time window:
-
-The following examples uploads local Uri resource, configured to run immediately (the default), with a maximum of 7 retries, and only on an unmetered network (e.g. wifi):
-
- String requestId = MediaManager.get().upload(uri)
- .unsigned("sample_app_preset")
- .constrain(TimeWindow.immediate())
- .policy(new RequestUploadPolicy.Builder().maxRetries(7).networkPolicy(RequestUploadPolicy.NetworkType.UNMETERED).build())
- .dispatch();
-
-For security reasons, mobile applications cannot contain the full account credentials, and so they cannot freely upload resources to the cloud.
-Cloudinary provides two different mechanisms to enable end-users to upload resources without providing full credentials.
+## Installation
-##### 1. Unsigned uploads using [Upload Presets.](https://cloudinary.com/documentation/android_image_and_video_upload)
-You can create an upload preset in your Cloudinary account console, defining rules that limit the formats, transformations, dimensions and more.
-Once the preset is defined, it's name is supplied when calling upload. An upload call will only succeed if the preset name is used and the resource is within the preset's pre-defined limits.
+Add the dependency to your app module `build.gradle`, with `mavenCentral()` in your repositories:
+
+```gradle
+implementation 'com.cloudinary:cloudinary-android:3.1.2'
+```
+
+With Maven, add it to `pom.xml` instead:
+
+```xml
+
+ com.cloudinary
+ cloudinary-android
+ 3.1.2
+ aar
+
+```
+
+## Configuration
+
+This SDK ships inside an installed app, so it never holds the API secret. It needs only the cloud name. Uploads run unsigned via upload presets, or signed by a server you control through a `SignatureProvider`. Keep the API key and secret out of the app and out of version control.
+
+Initialize `MediaManager` once, before any other SDK call — in your `Application.onCreate()`, not per-Activity. Set the cloud name programmatically:
+
+```java
+import com.cloudinary.android.MediaManager;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyApp extends android.app.Application {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Map config = new HashMap<>();
+ config.put("cloud_name", "my_cloud_name");
+ MediaManager.init(this, config);
+ }
+}
+```
+
+Or set a secret-free `CLOUDINARY_URL` as meta-data in `AndroidManifest.xml` and call the no-config overload — the value carries only the cloud name:
+
+```xml
+
+
+
+```
+
+```java
+import com.cloudinary.android.MediaManager;
+
+MediaManager.init(this); // reads CLOUDINARY_URL from the manifest meta-data
+```
+
+## Quick examples
+
+### Upload from the device
+
+`MediaManager.get().upload(...)` accepts a file-path `String`, a `Uri`, a `byte[]`, or a raw-resource `int` (there is no `File` overload — pass `file.getAbsolutePath()` for a file). The upload is dispatched to a background queue and retried on recoverable errors. `dispatch()` returns a `requestId` immediately; results arrive through the `UploadCallback`, whose `onSuccess` map holds `public_id` and `secure_url`. Requires `MediaManager` initialized (see Configuration).
+
+```java
+import android.net.Uri;
+import android.util.Log;
+import com.cloudinary.android.MediaManager;
+import com.cloudinary.android.callback.ErrorInfo;
+import com.cloudinary.android.callback.UploadCallback;
+import java.util.Map;
+
+String requestId = MediaManager.get().upload(imageUri)
+ .unsigned("my_preset") // an unsigned upload preset defined in your product environment
+ .option("public_id", "sample_id")
+ .callback(new UploadCallback() {
+ @Override public void onStart(String requestId) { }
+ @Override public void onProgress(String requestId, long bytes, long totalBytes) { }
+ @Override public void onSuccess(String requestId, Map resultData) {
+ Log.d("upload", resultData.get("public_id") + " " + resultData.get("secure_url"));
+ }
+ @Override public void onError(String requestId, ErrorInfo error) {
+ Log.e("upload", error.getDescription() + " (" + error.getCode() + ")");
+ }
+ @Override public void onReschedule(String requestId, ErrorInfo error) { }
+ })
+ .dispatch();
+```
-The following example uploads a local resource, available as a Uri, assuming a preset named 'sample_preset' already exists in the account:
+### Build and optimize a delivery URL
- String requestId = MediaManager.get().upload(uri).unsigned("sample_preset").dispatch();
+`MediaManager.get().url()` is synchronous and returns a string — no network call. This one scales `sample.jpg` to 400 px wide and lets Cloudinary pick the format and quality for the requesting device (`f_auto`, `q_auto`). Requires `MediaManager` initialized (see Configuration).
-##### 2. Signed uploads with server-based signature
-Another way to allow uploading without credentials is using signed uploads.
-It is recommended to generate the upload authentication signature on the server side, where it's safe to store the `api_secret`.
+```java
+import com.cloudinary.Transformation;
+import com.cloudinary.android.MediaManager;
-Cloudinary's Android SDK allows providing server-generated signature and any additional parameters that were generated on the server side (instead of signing using `api_secret` locally).
+String url = MediaManager.get().url()
+ .transformation(new Transformation()
+ .width(400).crop("scale").quality("auto").fetchFormat("auto"))
+ .generate("sample.jpg");
+// With cloud_name "demo": https://res.cloudinary.com/demo/image/upload/c_scale,f_auto,q_auto,w_400/sample.jpg
+```
-Your server can use any Cloudinary libraries (Ruby on Rails, PHP, Python & Django, Java, Perl, .Net, etc.) for generating the signature. The following JSON in an example of a response of an upload authorization request to your server:
+### Transform an asset with a face-detection thumbnail
- {
- "signature": "sgjfdoigfjdgfdogidf9g87df98gfdb8f7d6gfdg7gfd8",
- "public_id": "abdbasdasda76asd7sa789",
- "timestamp": 1346925631,
- "api_key": "123456789012345"
- }
+Chain transformation parameters on the same `url()` builder to crop to a face-detected 90×90 thumbnail. Requires `MediaManager` initialized (see Configuration).
-When initializing `MediaManager`, a `SignatureProvider` can be sent. Whenever an upload requires signing, the library will call the provider's `provideSignature()` method,
-where you should implement the call to your server's signing endpoint. This callback runs on a background a thread so there's no need to handle threading:
+```java
+import com.cloudinary.Transformation;
+import com.cloudinary.android.MediaManager;
- MediaManager.init(this, new SignatureProvider() {
- @Override
- public Signature provideSignature(Map options) {
- // call server signature endpoint
- }
- }, null);
+String thumb = MediaManager.get().url()
+ .transformation(new Transformation()
+ .width(90).height(90).crop("thumb").gravity("face"))
+ .generate("woman.jpg");
+// With cloud_name "demo": https://res.cloudinary.com/demo/image/upload/c_thumb,g_face,h_90,w_90/woman.jpg
+```
-## Contributions
-See [contributing guidelines](/CONTRIBUTING.md).
+## For AI agents
-## Get Help
-If you run into an issue or have a question, you can either:
-- [Open a Github issue](https://github.com/cloudinary/cloudinary_android/issues) (for issues related to the SDK)
-- [Open a support ticket](https://cloudinary.com/contact) (for issues related to your account)
+`cloudinary-android` is the native Android client SDK (Java/Kotlin): on-device upload through a background, retrying queue and in-app transformation and delivery URL building via `MediaManager`. It never holds the API secret — uploads are unsigned (upload presets) or signed by a server through a `SignatureProvider`. For tasks this package doesn't cover, choose a different package:
-## About Cloudinary
-Cloudinary is a powerful media API for websites and mobile apps alike, Cloudinary enables developers to efficiently manage, transform, optimize, and deliver images and videos through multiple CDNs. Ultimately, viewers enjoy responsive and personalized visual-media experiences—irrespective of the viewing device.
+| Task | Package |
+|---|---|
+| Native iOS app (Swift/Obj-C) | [`cloudinary_ios`](https://github.com/cloudinary/cloudinary_ios) |
+| Cross-platform React Native app | [`cloudinary-react-native`](https://github.com/cloudinary/cloudinary-react-native) |
+| Server-side JVM: signed uploads, Admin API, signature generation | [`cloudinary_java`](https://github.com/cloudinary/cloudinary_java) |
+| Full sample app to copy from | [`android-demo`](https://github.com/cloudinary/android-demo) |
+| Run Cloudinary operations as agent tools | [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers) |
-## Additional resources
+## Links
-- [Cloudinary Transformation and REST API References](https://cloudinary.com/documentation/cloudinary_references): Comprehensive references, including syntax and examples for all SDKs.
-- [MediaJams.dev](https://mediajams.dev/): Bite-size use-case tutorials written by and for Cloudinary Developers
-- [DevJams](https://www.youtube.com/playlist?list=PL8dVGjLA2oMr09amgERARsZyrOz_sPvqw): Cloudinary developer podcasts on YouTube.
-- [Cloudinary Academy](https://training.cloudinary.com/): Free self-paced courses, instructor-led virtual courses, and on-site courses.
-- [Code Explorers and Feature Demos](https://cloudinary.com/documentation/code_explorers_demos_index): A one-stop shop for all code explorers, Postman collections, and feature demos found in the docs.
-- [Cloudinary Roadmap](https://cloudinary.com/roadmap): Your chance to follow, vote, or suggest what Cloudinary should develop next.
-- [Cloudinary Facebook Community](https://www.facebook.com/groups/CloudinaryCommunity): Learn from and offer help to other Cloudinary developers.
-- [Cloudinary Account Registration](https://cloudinary.com/users/register/free): Free Cloudinary account registration.
-- [Cloudinary Website](https://cloudinary.com): Learn about Cloudinary's products, partners, customers, pricing, and more.
+- [Android SDK guide](https://cloudinary.com/documentation/android_integration)
+- [Upload (presets, callbacks, policy)](https://cloudinary.com/documentation/android_image_and_video_upload)
+- [Image transformation](https://cloudinary.com/documentation/android_image_manipulation)
+- [Video transformation](https://cloudinary.com/documentation/android_video_manipulation)
+- [Documentation llms.txt index](https://cloudinary.com/documentation/llms.txt)
+- [Package on Maven Central](https://central.sonatype.com/artifact/com.cloudinary/cloudinary-android)
-## Licence
Released under the MIT license.