From 233fca7b393403e0f5f62f0b7ecee36e09eead7a Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Wed, 25 Mar 2026 13:48:07 +0000 Subject: [PATCH 1/2] added new video param and README --- README.md | 382 ++++++++++++++++++ .../model/IONCAMRVideoParameters.kt | 3 +- 2 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..fdabb45 --- /dev/null +++ b/README.md @@ -0,0 +1,382 @@ +# IONCameraLib + +A modern, flexible and feature-rich camera and media library for Android apps. Includes advanced photo, video, and gallery management with easy integration for Kotlin and Android projects. + +## Installation + +### Gradle + +Add the following to your module's `build.gradle` file: + +```groovy +dependencies { + implementation 'io.ionic.libs:ioncameralib:1.0.0' +} +``` + +Make sure you have the appropriate Maven repository declared in your project-level `build.gradle` or `settings.gradle`: + +```groovy +repositories { + google() + mavenCentral() +} +``` + +## Usage + +### Basic Camera Operations + +```kotlin +import io.ionic.libs.ioncameralib.manager.IONCAMRCameraManager +import io.ionic.libs.ioncameralib.manager.IONCAMRGalleryManager +import io.ionic.libs.ioncameralib.manager.IONCAMREditManager +import io.ionic.libs.ioncameralib.manager.IONCAMRVideoManager +import io.ionic.libs.ioncameralib.model.IONCAMRCameraParameters +import io.ionic.libs.ioncameralib.model.IONCAMREditParameters +import io.ionic.libs.ioncameralib.model.IONCAMRVideoParameters +import io.ionic.libs.ioncameralib.model.IONCAMRMediaType + +class MainActivity : AppCompatActivity() { + + private lateinit var cameraManager: IONCAMRCameraManager + private lateinit var galleryManager: IONCAMRGalleryManager + private lateinit var editManager: IONCAMREditManager + private lateinit var videoManager: IONCAMRVideoManager + + // Store parameters to use in launcher callbacks + private var cameraParameters: IONCAMRCameraParameters? = null + private var videoParameters: IONCAMRVideoParameters? = null + private var editParameters: IONCAMREditParameters? = null + + // Launchers must be registered at class level (before the activity starts) + private val cameraLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + val params = cameraParameters ?: return@registerForActivityResult + cameraManager.processResultFromCamera( + activity = this, + intent = result.data, + camParameters = params, + onMediaResult = { mediaResult -> println("Photo captured: ${mediaResult.uri}") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + + private val videoLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + val params = videoParameters ?: return@registerForActivityResult + lifecycleScope.launch { + cameraManager.processResultFromVideo( + activity = this@MainActivity, + uri = result.data?.data, + fromGallery = params.saveToGallery, + isPersistent = params.isPersistent, + includeMetadata = params.includeMetadata, + onSuccess = { mediaResult -> println("Video captured: ${mediaResult.uri}") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + } + + private val galleryLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + lifecycleScope.launch { + galleryManager.onChooseFromGalleryResult( + activity = this@MainActivity, + resultCode = result.resultCode, + intent = result.data, + includeMetadata = false, + onSuccess = { results -> println("Selected ${results.size} item(s)") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + } + + private val editLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + val params = editParameters ?: IONCAMREditParameters( + editURI = null, fromUri = false, saveToGallery = false, includeMetadata = false + ) + editManager.processResultFromEdit( + activity = this, + intent = result.data, + editParameters = params, + onImage = { base64 -> println("Edited image (base64): $base64") }, + onMediaResult = { mediaResult -> println("Edited image URI: ${mediaResult.uri}") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupManagers() + } + + private fun setupManagers() { + val exifHelper = IONCAMRExifHelper() + val fileHelper = IONCAMRFileHelper() + val mediaHelper = IONCAMRMediaHelper() + val imageHelper = IONCAMRImageHelper() + + cameraManager = IONCAMRCameraManager( + applicationId = packageName, + exif = exifHelper, + fileHelper = fileHelper, + mediaHelper = mediaHelper, + imageHelper = imageHelper + ) + galleryManager = IONCAMRGalleryManager( + exif = exifHelper, + fileHelper = fileHelper, + mediaHelper = mediaHelper, + imageHelper = imageHelper + ) + editManager = IONCAMREditManager( + applicationId = packageName, + exif = exifHelper, + fileHelper = fileHelper, + mediaHelper = mediaHelper, + imageHelper = imageHelper + ) + videoManager = IONCAMRVideoManager(fileHelper = fileHelper) + } + + // Take a photo + fun capturePhoto() { + cameraParameters = IONCAMRCameraParameters( + mQuality = 80, + targetWidth = 1024, + targetHeight = 768, + encodingType = 0, // 0 = JPEG, 1 = PNG + mediaType = 0, + allowEdit = true, + correctOrientation = true, + saveToPhotoAlbum = false, + includeMetadata = false + ) + cameraManager.takePhoto( + activity = this, + encodingType = cameraParameters!!.encodingType, + launcher = cameraLauncher + ) + } + + // Record a video + fun recordVideo() { + videoParameters = IONCAMRVideoParameters( + saveToGallery = false, + includeMetadata = false, + isPersistent = true + ) + cameraManager.recordVideo( + activity = this, + saveVideoToGallery = videoParameters!!.saveToGallery, + launcher = videoLauncher, + onError = { error -> println("Error: ${error.description}") } + ) + } + + // Choose from gallery + fun chooseFromGallery() { + galleryManager.chooseFromGallery( + activity = this, + mediaType = IONCAMRMediaType.PICTURE, + allowMultiSelect = false, + limit = 1, + launcher = galleryLauncher + ) + } + + // Edit an image from URI + fun editURIPhoto(filePath: String) { + editParameters = IONCAMREditParameters( + editURI = filePath, + fromUri = true, + saveToGallery = false, + includeMetadata = false + ) + editManager.editURIPicture( + activity = this, + pictureFilePath = filePath, + launcher = editLauncher, + onError = { error -> println("Error: ${error.description}") } + ) + } + + // Edit an image from Base64 string + fun editBase64Image(base64Image: String) { + editParameters = null + editManager.editImage( + activity = this, + image = base64Image, + launcher = editLauncher + ) + } + + // Play a video + fun playVideo(videoUri: String) { + videoManager.playVideo( + activity = this, + videoUri = videoUri, + onSuccess = { println("Video playback started") }, + onError = { error -> println("Video playback error: ${error.description}") } + ) + } + + // Clean temporary video files + fun cleanupTemporaryFiles() { + cameraManager.deleteVideoFilesFromCache(this) + } + + override fun onDestroy() { + super.onDestroy() + cameraManager.onDestroy(this) + } +} +``` + +### Advanced Usage Examples + +```kotlin +// Multiple selection from gallery (video or photo) +fun selectMultipleMedia() { + galleryManager.chooseFromGallery( + activity = this, + mediaType = IONCAMRMediaType.ALL, + allowMultiSelect = true, + limit = 10, + launcher = galleryLauncher + ) +} + +// High quality photo with metadata +fun takeHighQualityPhoto() { + cameraParameters = IONCAMRCameraParameters( + mQuality = 100, + targetWidth = 2048, + targetHeight = 1536, + encodingType = 0, // JPEG + mediaType = 0, + allowEdit = false, + correctOrientation = true, + saveToPhotoAlbum = true, + includeMetadata = true + ) + cameraManager.takePhoto( + activity = this, + encodingType = cameraParameters!!.encodingType, + launcher = cameraLauncher + ) +} + +// Video recording saved to gallery +fun recordVideoToGallery() { + videoParameters = IONCAMRVideoParameters( + saveToGallery = true, + includeMetadata = false, + isPersistent = true + ) + cameraManager.recordVideo( + activity = this, + saveVideoToGallery = videoParameters!!.saveToGallery, + launcher = videoLauncher, + onError = { error -> println("Error: ${error.description}") } + ) +} +``` + +## Key Components + +### Manager Classes + +- **`IONCAMRCameraManager`**: Handles photo capture and video recording via the device camera +- **`IONCAMRGalleryManager`**: Handles media selection from the device gallery +- **`IONCAMREditManager`**: Handles photo editing and cropping +- **`IONCAMRVideoManager`**: Handles video playback + +### Configuration Parameters + +- **`IONCAMRCameraParameters`**: Configures photo capture settings (quality, dimensions, encoding type, media type, edit, orientation correction, album saving, metadata) +- **`IONCAMRVideoParameters`**: Configures video recording settings (save to gallery, include metadata, persistence) +- **`IONCAMREditParameters`**: Configures image editing settings (source URI, save to gallery, metadata) + +### Result Model + +All successful media operations return `IONCAMRMediaResult` objects: + +```kotlin +data class IONCAMRMediaResult( + val type: Int, // Media type (image or video) + val uri: String, // File URI of the captured or selected media item + val thumbnail: String?, // Base64 thumbnail (if available) + val metadata: IONCAMRMediaMetadata?, // File metadata (if requested) + val saved: Boolean // Whether the file was saved to the gallery +) + +data class IONCAMRMediaMetadata( + val size: Long?, // File size in bytes + val duration: Int?, // Duration in seconds (video only) + val format: String?, // File format (e.g. "jpeg", "mp4") + val resolution: String?, // Image/video resolution (e.g. "1920x1080") + val creationDate: String? // File creation date +) +``` + +### Error Handling + +All manager methods expose an `onError` callback that receives an `IONCAMRError`. Each error carries a numeric `code` and a human-readable `description`. Errors are grouped into categories: permission errors, user cancellations, file errors, and general processing errors. See `IONCAMRError` for the full list. + +```kotlin +onError = { error -> + // error.code — numeric error code (e.g. for logging) + // error.description — human-readable message + showErrorAlert("Error ${error.code}: ${error.description}") +} +``` + +## Permissions + +Add the following permissions to your app's `AndroidManifest.xml`: + +```xml + + + + + + + +``` + +You must also request camera and storage permissions at runtime before invoking camera or gallery operations. Use Android's standard permission request flow or a library such as [ActivityResultContracts.RequestPermission](https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.RequestPermission). + +## Requirements + +- Android API 24+ +- Android Gradle Plugin 8.7.3+ +- Kotlin 1.9.24+ +- Java 17+ + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Contributing + +1. Fork the project +2. Create your feature branch (`git checkout -b feature/AmazingFeature`) +3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +## Support + +- Report issues on our [Issue Tracker](https://github.com/ionic-team/ion-android-camera/issues) diff --git a/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRVideoParameters.kt b/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRVideoParameters.kt index 119a6ab..6fe39fb 100644 --- a/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRVideoParameters.kt +++ b/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRVideoParameters.kt @@ -4,5 +4,6 @@ import com.google.gson.annotations.SerializedName data class IONCAMRVideoParameters( @SerializedName("saveToGallery") val saveToGallery: Boolean, - @SerializedName("includeMetadata") val includeMetadata: Boolean + @SerializedName("includeMetadata") val includeMetadata: Boolean, + @SerializedName("isPersistent") val isPersistent: Boolean = true ) From a3f99fc2ee0266b1b4ce88dd912229f6fcbdb920 Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Wed, 25 Mar 2026 13:58:20 +0000 Subject: [PATCH 2/2] remove README from root --- README.md | 382 ------------------------------------------------ docs/README.md | 388 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 360 insertions(+), 410 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index fdabb45..0000000 --- a/README.md +++ /dev/null @@ -1,382 +0,0 @@ -# IONCameraLib - -A modern, flexible and feature-rich camera and media library for Android apps. Includes advanced photo, video, and gallery management with easy integration for Kotlin and Android projects. - -## Installation - -### Gradle - -Add the following to your module's `build.gradle` file: - -```groovy -dependencies { - implementation 'io.ionic.libs:ioncameralib:1.0.0' -} -``` - -Make sure you have the appropriate Maven repository declared in your project-level `build.gradle` or `settings.gradle`: - -```groovy -repositories { - google() - mavenCentral() -} -``` - -## Usage - -### Basic Camera Operations - -```kotlin -import io.ionic.libs.ioncameralib.manager.IONCAMRCameraManager -import io.ionic.libs.ioncameralib.manager.IONCAMRGalleryManager -import io.ionic.libs.ioncameralib.manager.IONCAMREditManager -import io.ionic.libs.ioncameralib.manager.IONCAMRVideoManager -import io.ionic.libs.ioncameralib.model.IONCAMRCameraParameters -import io.ionic.libs.ioncameralib.model.IONCAMREditParameters -import io.ionic.libs.ioncameralib.model.IONCAMRVideoParameters -import io.ionic.libs.ioncameralib.model.IONCAMRMediaType - -class MainActivity : AppCompatActivity() { - - private lateinit var cameraManager: IONCAMRCameraManager - private lateinit var galleryManager: IONCAMRGalleryManager - private lateinit var editManager: IONCAMREditManager - private lateinit var videoManager: IONCAMRVideoManager - - // Store parameters to use in launcher callbacks - private var cameraParameters: IONCAMRCameraParameters? = null - private var videoParameters: IONCAMRVideoParameters? = null - private var editParameters: IONCAMREditParameters? = null - - // Launchers must be registered at class level (before the activity starts) - private val cameraLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { result -> - val params = cameraParameters ?: return@registerForActivityResult - cameraManager.processResultFromCamera( - activity = this, - intent = result.data, - camParameters = params, - onMediaResult = { mediaResult -> println("Photo captured: ${mediaResult.uri}") }, - onError = { error -> println("Error: ${error.description}") } - ) - } - - private val videoLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { result -> - val params = videoParameters ?: return@registerForActivityResult - lifecycleScope.launch { - cameraManager.processResultFromVideo( - activity = this@MainActivity, - uri = result.data?.data, - fromGallery = params.saveToGallery, - isPersistent = params.isPersistent, - includeMetadata = params.includeMetadata, - onSuccess = { mediaResult -> println("Video captured: ${mediaResult.uri}") }, - onError = { error -> println("Error: ${error.description}") } - ) - } - } - - private val galleryLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { result -> - lifecycleScope.launch { - galleryManager.onChooseFromGalleryResult( - activity = this@MainActivity, - resultCode = result.resultCode, - intent = result.data, - includeMetadata = false, - onSuccess = { results -> println("Selected ${results.size} item(s)") }, - onError = { error -> println("Error: ${error.description}") } - ) - } - } - - private val editLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { result -> - val params = editParameters ?: IONCAMREditParameters( - editURI = null, fromUri = false, saveToGallery = false, includeMetadata = false - ) - editManager.processResultFromEdit( - activity = this, - intent = result.data, - editParameters = params, - onImage = { base64 -> println("Edited image (base64): $base64") }, - onMediaResult = { mediaResult -> println("Edited image URI: ${mediaResult.uri}") }, - onError = { error -> println("Error: ${error.description}") } - ) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setupManagers() - } - - private fun setupManagers() { - val exifHelper = IONCAMRExifHelper() - val fileHelper = IONCAMRFileHelper() - val mediaHelper = IONCAMRMediaHelper() - val imageHelper = IONCAMRImageHelper() - - cameraManager = IONCAMRCameraManager( - applicationId = packageName, - exif = exifHelper, - fileHelper = fileHelper, - mediaHelper = mediaHelper, - imageHelper = imageHelper - ) - galleryManager = IONCAMRGalleryManager( - exif = exifHelper, - fileHelper = fileHelper, - mediaHelper = mediaHelper, - imageHelper = imageHelper - ) - editManager = IONCAMREditManager( - applicationId = packageName, - exif = exifHelper, - fileHelper = fileHelper, - mediaHelper = mediaHelper, - imageHelper = imageHelper - ) - videoManager = IONCAMRVideoManager(fileHelper = fileHelper) - } - - // Take a photo - fun capturePhoto() { - cameraParameters = IONCAMRCameraParameters( - mQuality = 80, - targetWidth = 1024, - targetHeight = 768, - encodingType = 0, // 0 = JPEG, 1 = PNG - mediaType = 0, - allowEdit = true, - correctOrientation = true, - saveToPhotoAlbum = false, - includeMetadata = false - ) - cameraManager.takePhoto( - activity = this, - encodingType = cameraParameters!!.encodingType, - launcher = cameraLauncher - ) - } - - // Record a video - fun recordVideo() { - videoParameters = IONCAMRVideoParameters( - saveToGallery = false, - includeMetadata = false, - isPersistent = true - ) - cameraManager.recordVideo( - activity = this, - saveVideoToGallery = videoParameters!!.saveToGallery, - launcher = videoLauncher, - onError = { error -> println("Error: ${error.description}") } - ) - } - - // Choose from gallery - fun chooseFromGallery() { - galleryManager.chooseFromGallery( - activity = this, - mediaType = IONCAMRMediaType.PICTURE, - allowMultiSelect = false, - limit = 1, - launcher = galleryLauncher - ) - } - - // Edit an image from URI - fun editURIPhoto(filePath: String) { - editParameters = IONCAMREditParameters( - editURI = filePath, - fromUri = true, - saveToGallery = false, - includeMetadata = false - ) - editManager.editURIPicture( - activity = this, - pictureFilePath = filePath, - launcher = editLauncher, - onError = { error -> println("Error: ${error.description}") } - ) - } - - // Edit an image from Base64 string - fun editBase64Image(base64Image: String) { - editParameters = null - editManager.editImage( - activity = this, - image = base64Image, - launcher = editLauncher - ) - } - - // Play a video - fun playVideo(videoUri: String) { - videoManager.playVideo( - activity = this, - videoUri = videoUri, - onSuccess = { println("Video playback started") }, - onError = { error -> println("Video playback error: ${error.description}") } - ) - } - - // Clean temporary video files - fun cleanupTemporaryFiles() { - cameraManager.deleteVideoFilesFromCache(this) - } - - override fun onDestroy() { - super.onDestroy() - cameraManager.onDestroy(this) - } -} -``` - -### Advanced Usage Examples - -```kotlin -// Multiple selection from gallery (video or photo) -fun selectMultipleMedia() { - galleryManager.chooseFromGallery( - activity = this, - mediaType = IONCAMRMediaType.ALL, - allowMultiSelect = true, - limit = 10, - launcher = galleryLauncher - ) -} - -// High quality photo with metadata -fun takeHighQualityPhoto() { - cameraParameters = IONCAMRCameraParameters( - mQuality = 100, - targetWidth = 2048, - targetHeight = 1536, - encodingType = 0, // JPEG - mediaType = 0, - allowEdit = false, - correctOrientation = true, - saveToPhotoAlbum = true, - includeMetadata = true - ) - cameraManager.takePhoto( - activity = this, - encodingType = cameraParameters!!.encodingType, - launcher = cameraLauncher - ) -} - -// Video recording saved to gallery -fun recordVideoToGallery() { - videoParameters = IONCAMRVideoParameters( - saveToGallery = true, - includeMetadata = false, - isPersistent = true - ) - cameraManager.recordVideo( - activity = this, - saveVideoToGallery = videoParameters!!.saveToGallery, - launcher = videoLauncher, - onError = { error -> println("Error: ${error.description}") } - ) -} -``` - -## Key Components - -### Manager Classes - -- **`IONCAMRCameraManager`**: Handles photo capture and video recording via the device camera -- **`IONCAMRGalleryManager`**: Handles media selection from the device gallery -- **`IONCAMREditManager`**: Handles photo editing and cropping -- **`IONCAMRVideoManager`**: Handles video playback - -### Configuration Parameters - -- **`IONCAMRCameraParameters`**: Configures photo capture settings (quality, dimensions, encoding type, media type, edit, orientation correction, album saving, metadata) -- **`IONCAMRVideoParameters`**: Configures video recording settings (save to gallery, include metadata, persistence) -- **`IONCAMREditParameters`**: Configures image editing settings (source URI, save to gallery, metadata) - -### Result Model - -All successful media operations return `IONCAMRMediaResult` objects: - -```kotlin -data class IONCAMRMediaResult( - val type: Int, // Media type (image or video) - val uri: String, // File URI of the captured or selected media item - val thumbnail: String?, // Base64 thumbnail (if available) - val metadata: IONCAMRMediaMetadata?, // File metadata (if requested) - val saved: Boolean // Whether the file was saved to the gallery -) - -data class IONCAMRMediaMetadata( - val size: Long?, // File size in bytes - val duration: Int?, // Duration in seconds (video only) - val format: String?, // File format (e.g. "jpeg", "mp4") - val resolution: String?, // Image/video resolution (e.g. "1920x1080") - val creationDate: String? // File creation date -) -``` - -### Error Handling - -All manager methods expose an `onError` callback that receives an `IONCAMRError`. Each error carries a numeric `code` and a human-readable `description`. Errors are grouped into categories: permission errors, user cancellations, file errors, and general processing errors. See `IONCAMRError` for the full list. - -```kotlin -onError = { error -> - // error.code — numeric error code (e.g. for logging) - // error.description — human-readable message - showErrorAlert("Error ${error.code}: ${error.description}") -} -``` - -## Permissions - -Add the following permissions to your app's `AndroidManifest.xml`: - -```xml - - - - - - - -``` - -You must also request camera and storage permissions at runtime before invoking camera or gallery operations. Use Android's standard permission request flow or a library such as [ActivityResultContracts.RequestPermission](https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.RequestPermission). - -## Requirements - -- Android API 24+ -- Android Gradle Plugin 8.7.3+ -- Kotlin 1.9.24+ -- Java 17+ - -## License - -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - -## Contributing - -1. Fork the project -2. Create your feature branch (`git checkout -b feature/AmazingFeature`) -3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) -4. Push to the branch (`git push origin feature/AmazingFeature`) -5. Open a Pull Request - -## Support - -- Report issues on our [Issue Tracker](https://github.com/ionic-team/ion-android-camera/issues) diff --git a/docs/README.md b/docs/README.md index f8fda40..fdabb45 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,50 +1,382 @@ -# ion-android-camera +# IONCameraLib -Welcome to **ion-android-camera**. This repository serves as a template to create repositories used to build Android libraries. This file will guide you through that process, that is defined by two sequential steps: +A modern, flexible and feature-rich camera and media library for Android apps. Includes advanced photo, video, and gallery management with easy integration for Kotlin and Android projects. -1. Use the current repository as the template for the new one. -2. Clone the new repository on our machine. -3. Run a script that updates the created repository with the correct information. +## Installation -These steps are detailed in the next sections. +### Gradle -:warning: Every step listed here must be successfully completed before you start working on the new repository. +Add the following to your module's `build.gradle` file: -## Create a Repository Based on the Template +```groovy +dependencies { + implementation 'io.ionic.libs:ioncameralib:1.0.0' +} +``` + +Make sure you have the appropriate Maven repository declared in your project-level `build.gradle` or `settings.gradle`: + +```groovy +repositories { + google() + mavenCentral() +} +``` + +## Usage + +### Basic Camera Operations + +```kotlin +import io.ionic.libs.ioncameralib.manager.IONCAMRCameraManager +import io.ionic.libs.ioncameralib.manager.IONCAMRGalleryManager +import io.ionic.libs.ioncameralib.manager.IONCAMREditManager +import io.ionic.libs.ioncameralib.manager.IONCAMRVideoManager +import io.ionic.libs.ioncameralib.model.IONCAMRCameraParameters +import io.ionic.libs.ioncameralib.model.IONCAMREditParameters +import io.ionic.libs.ioncameralib.model.IONCAMRVideoParameters +import io.ionic.libs.ioncameralib.model.IONCAMRMediaType + +class MainActivity : AppCompatActivity() { + + private lateinit var cameraManager: IONCAMRCameraManager + private lateinit var galleryManager: IONCAMRGalleryManager + private lateinit var editManager: IONCAMREditManager + private lateinit var videoManager: IONCAMRVideoManager + + // Store parameters to use in launcher callbacks + private var cameraParameters: IONCAMRCameraParameters? = null + private var videoParameters: IONCAMRVideoParameters? = null + private var editParameters: IONCAMREditParameters? = null + + // Launchers must be registered at class level (before the activity starts) + private val cameraLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + val params = cameraParameters ?: return@registerForActivityResult + cameraManager.processResultFromCamera( + activity = this, + intent = result.data, + camParameters = params, + onMediaResult = { mediaResult -> println("Photo captured: ${mediaResult.uri}") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + + private val videoLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + val params = videoParameters ?: return@registerForActivityResult + lifecycleScope.launch { + cameraManager.processResultFromVideo( + activity = this@MainActivity, + uri = result.data?.data, + fromGallery = params.saveToGallery, + isPersistent = params.isPersistent, + includeMetadata = params.includeMetadata, + onSuccess = { mediaResult -> println("Video captured: ${mediaResult.uri}") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + } + + private val galleryLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + lifecycleScope.launch { + galleryManager.onChooseFromGalleryResult( + activity = this@MainActivity, + resultCode = result.resultCode, + intent = result.data, + includeMetadata = false, + onSuccess = { results -> println("Selected ${results.size} item(s)") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + } + + private val editLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + val params = editParameters ?: IONCAMREditParameters( + editURI = null, fromUri = false, saveToGallery = false, includeMetadata = false + ) + editManager.processResultFromEdit( + activity = this, + intent = result.data, + editParameters = params, + onImage = { base64 -> println("Edited image (base64): $base64") }, + onMediaResult = { mediaResult -> println("Edited image URI: ${mediaResult.uri}") }, + onError = { error -> println("Error: ${error.description}") } + ) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupManagers() + } + + private fun setupManagers() { + val exifHelper = IONCAMRExifHelper() + val fileHelper = IONCAMRFileHelper() + val mediaHelper = IONCAMRMediaHelper() + val imageHelper = IONCAMRImageHelper() + + cameraManager = IONCAMRCameraManager( + applicationId = packageName, + exif = exifHelper, + fileHelper = fileHelper, + mediaHelper = mediaHelper, + imageHelper = imageHelper + ) + galleryManager = IONCAMRGalleryManager( + exif = exifHelper, + fileHelper = fileHelper, + mediaHelper = mediaHelper, + imageHelper = imageHelper + ) + editManager = IONCAMREditManager( + applicationId = packageName, + exif = exifHelper, + fileHelper = fileHelper, + mediaHelper = mediaHelper, + imageHelper = imageHelper + ) + videoManager = IONCAMRVideoManager(fileHelper = fileHelper) + } + + // Take a photo + fun capturePhoto() { + cameraParameters = IONCAMRCameraParameters( + mQuality = 80, + targetWidth = 1024, + targetHeight = 768, + encodingType = 0, // 0 = JPEG, 1 = PNG + mediaType = 0, + allowEdit = true, + correctOrientation = true, + saveToPhotoAlbum = false, + includeMetadata = false + ) + cameraManager.takePhoto( + activity = this, + encodingType = cameraParameters!!.encodingType, + launcher = cameraLauncher + ) + } + + // Record a video + fun recordVideo() { + videoParameters = IONCAMRVideoParameters( + saveToGallery = false, + includeMetadata = false, + isPersistent = true + ) + cameraManager.recordVideo( + activity = this, + saveVideoToGallery = videoParameters!!.saveToGallery, + launcher = videoLauncher, + onError = { error -> println("Error: ${error.description}") } + ) + } + + // Choose from gallery + fun chooseFromGallery() { + galleryManager.chooseFromGallery( + activity = this, + mediaType = IONCAMRMediaType.PICTURE, + allowMultiSelect = false, + limit = 1, + launcher = galleryLauncher + ) + } + + // Edit an image from URI + fun editURIPhoto(filePath: String) { + editParameters = IONCAMREditParameters( + editURI = filePath, + fromUri = true, + saveToGallery = false, + includeMetadata = false + ) + editManager.editURIPicture( + activity = this, + pictureFilePath = filePath, + launcher = editLauncher, + onError = { error -> println("Error: ${error.description}") } + ) + } -First, we need to create a new repository. To accomplish this, please press the **Use this template** button available on the repository's GitHub webpage. + // Edit an image from Base64 string + fun editBase64Image(base64Image: String) { + editParameters = null + editManager.editImage( + activity = this, + image = base64Image, + launcher = editLauncher + ) + } -![Use this template button](./assets/useThisTemplateButton.png) + // Play a video + fun playVideo(videoUri: String) { + videoManager.playVideo( + activity = this, + videoUri = videoUri, + onSuccess = { println("Video playback started") }, + onError = { error -> println("Video playback error: ${error.description}") } + ) + } -Next, we have to define the new repository's name. In order to get the maximum performance of the following step, we advise you to use the **[ProjectName]Lib-Android** format for the name. The names used for the **Health and Fitness** and the **Social Logins** are valid examples of the expected format (_OSHealthFitnessLib-Android_ and _OSSocialLoginsLib-Android_ respectively). + // Clean temporary video files + fun cleanupTemporaryFiles() { + cameraManager.deleteVideoFilesFromCache(this) + } -The following image shows an example of the creation of a repository for the Android' Payments Library. + override fun onDestroy() { + super.onDestroy() + cameraManager.onDestroy(this) + } +} +``` + +### Advanced Usage Examples + +```kotlin +// Multiple selection from gallery (video or photo) +fun selectMultipleMedia() { + galleryManager.chooseFromGallery( + activity = this, + mediaType = IONCAMRMediaType.ALL, + allowMultiSelect = true, + limit = 10, + launcher = galleryLauncher + ) +} + +// High quality photo with metadata +fun takeHighQualityPhoto() { + cameraParameters = IONCAMRCameraParameters( + mQuality = 100, + targetWidth = 2048, + targetHeight = 1536, + encodingType = 0, // JPEG + mediaType = 0, + allowEdit = false, + correctOrientation = true, + saveToPhotoAlbum = true, + includeMetadata = true + ) + cameraManager.takePhoto( + activity = this, + encodingType = cameraParameters!!.encodingType, + launcher = cameraLauncher + ) +} + +// Video recording saved to gallery +fun recordVideoToGallery() { + videoParameters = IONCAMRVideoParameters( + saveToGallery = true, + includeMetadata = false, + isPersistent = true + ) + cameraManager.recordVideo( + activity = this, + saveVideoToGallery = videoParameters!!.saveToGallery, + launcher = videoLauncher, + onError = { error -> println("Error: ${error.description}") } + ) +} +``` -![Example for payments repository name](./assets/repositoryNameExample.png) +## Key Components -After filling up the form as needed, the last step to effectively create the repository is the click on the **Create repository from template** button. +### Manager Classes -![Create repository from template button](./assets/createRepositoryButton.png) +- **`IONCAMRCameraManager`**: Handles photo capture and video recording via the device camera +- **`IONCAMRGalleryManager`**: Handles media selection from the device gallery +- **`IONCAMREditManager`**: Handles photo editing and cropping +- **`IONCAMRVideoManager`**: Handles video playback -## Clone the New Repository +### Configuration Parameters -After completing the previous step, the next one is something common done in every repository a developer needs to do work on: clone the repository on the local machine. +- **`IONCAMRCameraParameters`**: Configures photo capture settings (quality, dimensions, encoding type, media type, edit, orientation correction, album saving, metadata) +- **`IONCAMRVideoParameters`**: Configures video recording settings (save to gallery, include metadata, persistence) +- **`IONCAMREditParameters`**: Configures image editing settings (source URI, save to gallery, metadata) -## Run the **generator_script.sh** +### Result Model -To finish the process, we just have one last thing to do. Run the **generator_script.sh** script that automates a couple of changes we need to apply. It is included in the _scripts_ folder. +All successful media operations return `IONCAMRMediaResult` objects: -To run the script, please execute the following commands on **Terminal**: +```kotlin +data class IONCAMRMediaResult( + val type: Int, // Media type (image or video) + val uri: String, // File URI of the captured or selected media item + val thumbnail: String?, // Base64 thumbnail (if available) + val metadata: IONCAMRMediaMetadata?, // File metadata (if requested) + val saved: Boolean // Whether the file was saved to the gallery +) +data class IONCAMRMediaMetadata( + val size: Long?, // File size in bytes + val duration: Int?, // Duration in seconds (video only) + val format: String?, // File format (e.g. "jpeg", "mp4") + val resolution: String?, // Image/video resolution (e.g. "1920x1080") + val creationDate: String? // File creation date +) ``` -cd scripts -sh generator_script.sh + +### Error Handling + +All manager methods expose an `onError` callback that receives an `IONCAMRError`. Each error carries a numeric `code` and a human-readable `description`. Errors are grouped into categories: permission errors, user cancellations, file errors, and general processing errors. See `IONCAMRError` for the full list. + +```kotlin +onError = { error -> + // error.code — numeric error code (e.g. for logging) + // error.description — human-readable message + showErrorAlert("Error ${error.code}: ${error.description}") +} ``` -Here's the complete list of what the script does: +## Permissions + +Add the following permissions to your app's `AndroidManifest.xml`: + +```xml + + + + + + + +``` + +You must also request camera and storage permissions at runtime before invoking camera or gallery operations. Use Android's standard permission request flow or a library such as [ActivityResultContracts.RequestPermission](https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.RequestPermission). + +## Requirements + +- Android API 24+ +- Android Gradle Plugin 8.7.3+ +- Kotlin 1.9.24+ +- Java 17+ + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Contributing + +1. Fork the project +2. Create your feature branch (`git checkout -b feature/AmazingFeature`) +3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +## Support -- The script provides a bit of information, such as mentioning the name that it will use as the Library name (its based on the one you used while creating the repository on GitHub). -- Requests the user for the application's package identifier. The format required is provided and needs to be complied with in order to advance. -- It informs that the script itself will be deleted, as it is a one time execution only. -- It performs the needed changes, replacing all placeholder's organisational identifier and library name for the ones provided by the user. -- To conclude, the script commits and pushes the changes to the remote repository. +- Report issues on our [Issue Tracker](https://github.com/ionic-team/ion-android-camera/issues)