Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
## Changelog

**[Unreleased] - Android 14 (API 34) Support**

✨ **Major Update: Full Android 14 Granular Media Permissions Support**

- **New Features:**
- Full support for `READ_MEDIA_VISUAL_USER_SELECTED` permission
- Automatic detection of partial vs full media access
- Permission upgrade flow for better user experience
- New `GranularPermissionConfig` for customizing permission behavior
- Extension functions: `enableGranularPermissions()`, `requireFullMediaAccess()`,
`minimalPermissionUI()`

- **Enhanced Permission Handling:**
- `MediaPermissionHelper` class for centralized permission logic
- Smart permission state detection across Android versions
- Graceful degradation when only partial access is granted
- Enhanced file loader to handle limited media access scenarios

- **Improved User Experience:**
- Non-intrusive upgrade prompts for partial access users
- Customizable messages for permission states
- Backward compatible - no breaking changes
- Works seamlessly on Android 13 and below

- **Documentation:**
- Complete Android 14 migration guide
- Updated sample app with granular permission examples
- Enhanced README with Android 14 information

- **Technical Details:**
- Added `READ_MEDIA_VISUAL_USER_SELECTED` permission to manifest
- Enhanced `ImagePickerFragment` with granular permission logic
- Updated `DefaultImageFileLoader` for partial access scenarios
- New configuration options in `ImagePickerConfig`
- Comprehensive permission state management

βœ… **Fully backward compatible - no breaking changes**

**2.4.0**
- Add `getUri()` for convenient [#285](https://github.com/esafirm/android-image-picker/pull/285)
- Fixes for Android Q [#290](https://github.com/esafirm/android-image-picker/pull/290) [#293](https://github.com/esafirm/android-image-picker/pull/293)
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ dependencies {

change `x.y.z` to version in the [release page](https://github.com/esafirm/android-image-picker/releases)

## Android 14 (API 34) Support

βœ… **Fully supports Android 14's granular media permissions**

The library automatically handles Android 14's new permission model where users can choose between:

- **"Select photos and videos"** - Partial access to user-selected media
- **"Allow access to all media"** - Full access to all media

```kotlin
val config = ImagePickerConfig()
.enableGranularPermissions() // Best user experience for Android 14+

// Or use legacy behavior
val config = ImagePickerConfig()
.requireFullMediaAccess() // Always require full access
```

πŸ“– **[Complete Android 14 Migration Guide](docs/android_14_migration.md)**

# Usage

For full example, please refer to the `sample` app.
Expand Down Expand Up @@ -129,6 +149,8 @@ You also still can use the `DefaultCameraModule` but discouraged to do it.

# Wiki

- [Android 14 Migration Guide](docs/android_14_migration.md) - **New!** Complete guide for Android
14 support
- [Custom components](https://github.com/esafirm/android-image-picker/blob/main/docs/custom_components.md)
- [Using another image library](https://github.com/esafirm/android-image-picker/blob/main/docs/another_image_library.md)
- [Return mode](https://github.com/esafirm/android-image-picker/blob/main/docs/return_mode.md)
Expand Down
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.android.tools.build:gradle:8.13.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

ext {
sdk = [
compileSdk: 33,
targetSdk : 33,
compileSdk: 34,
targetSdk : 34,
minSdk : 21
]
}
Expand Down
257 changes: 257 additions & 0 deletions docs/android_14_migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
# Android 14 (API 34) Migration Guide

This guide explains how to migrate your Android Image Picker library to support Android 14's new
granular media permissions.

## Overview

Android 14 introduces **granular media permissions** that give users more control over their media
access:

- **Full Access**: Traditional behavior - app can access all photos and videos
- **Partial Access**: New option - app can only access user-selected photos and videos

## What Changed

### Before Android 14

```
User grants permission β†’ App gets access to ALL media
```

### Android 14+

```
User sees dialog with two options:
1. "Select photos and videos" β†’ Partial access (READ_MEDIA_VISUAL_USER_SELECTED)
2. "Allow access to all media" β†’ Full access (READ_MEDIA_IMAGES + READ_MEDIA_VIDEO)
```

## Migration Steps

### 1. Update Your Manifest

The library now includes the new permission automatically:

```xml
<!-- Android 14+ granular media permissions -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
```

### 2. Update Your Code

#### Basic Usage (Recommended)

```kotlin
val imagePickerLauncher = registerImagePicker { images ->
// Handle selected images
}

// Use default granular permission behavior
val config = ImagePickerConfig()
.enableGranularPermissions() // Best user experience

imagePickerLauncher.launch(config)
```

#### Advanced Configuration

```kotlin
val config = ImagePickerConfig()
.granularPermissions {
showUpgradePrompt = true // Show "access all photos" option
requestFullAccessFirst = false // Start with partial access
allowPartialAccess = true // Allow app to work with limited access
partialAccessMessage = "Custom message for partial access"
showPartialAccessIndicator = true // Show UI indicator
}
```

#### Legacy Behavior (Always Require Full Access)

```kotlin
val config = ImagePickerConfig()
.requireFullMediaAccess() // Forces full access like before Android 14
```

#### Minimal UI (No Upgrade Prompts)

```kotlin
val config = ImagePickerConfig()
.minimalPermissionUI() // Works with partial access, no upgrade prompts
```

## Permission States

The library automatically handles different permission states:

| State | Description | User Experience |
|--------------------|---------------------------|--------------------------------------------------------|
| **Full Access** | Traditional behavior | All photos/videos available |
| **Partial Access** | Limited to user selection | Only selected photos/videos available + upgrade option |
| **No Access** | No permissions granted | Permission request dialog |

## User Experience Flow

### Default Behavior (Recommended)

1. **First Launch**: User sees Android's granular permission dialog
2. **User Chooses "Select photos"**: App works with limited access + shows upgrade option
3. **User Chooses "Allow all"**: App works with full access
4. **Upgrade Flow**: User can upgrade from partial to full access anytime

### Example Upgrade Flow

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Image Picker β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ IMG β”‚ β”‚ IMG β”‚ β”‚ IMG β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ ⚠️ Showing limited photos β”‚
β”‚ [Tap to see all photos] ←──────┼── Upgrade prompt
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

## Configuration Options

### GranularPermissionConfig Properties

```kotlin
data class GranularPermissionConfig(
// Show upgrade prompt when user has partial access
val showUpgradePrompt: Boolean = true,

// Request full access on first launch (vs. letting user choose)
val requestFullAccessFirst: Boolean = false,

// Custom message for partial access prompt
val partialAccessMessage: String? = null,

// Show indicator when in partial access mode
val showPartialAccessIndicator: Boolean = true,

// Allow app to work with partial access
val allowPartialAccess: Boolean = true
)
```

### Preset Configurations

```kotlin
// Best user experience (default)
GranularPermissionConfig.default()

// Legacy behavior - always require full access
GranularPermissionConfig.requireFullAccess()

// Minimal UI - no upgrade prompts
GranularPermissionConfig.minimal()
```

## Backward Compatibility

βœ… **Fully backward compatible** - no breaking changes

- Android 13 and below: Works exactly as before
- Android 14+: Adds granular permission support
- Existing code: Continues to work without changes

## Testing

### Test Scenarios

1. **Fresh Install on Android 14**:
- Test both "Select photos" and "Allow all" choices
- Verify upgrade flow works

2. **Permission Revocation**:
- Test app behavior when permissions are revoked
- Verify graceful degradation

3. **Backward Compatibility**:
- Test on Android 13 and below
- Ensure no regressions

### Testing Commands

```bash
# Test on Android 14 emulator
adb shell pm grant com.yourapp.package android.permission.READ_MEDIA_VISUAL_USER_SELECTED

# Revoke permissions for testing
adb shell pm revoke com.yourapp.package android.permission.READ_MEDIA_IMAGES
```

## Troubleshooting

### Common Issues

**Q: Users can't see all their photos**
A: This is expected with partial access. The upgrade prompt should guide users to grant full access.

**Q: App crashes on Android 14**
A: Ensure you're using the latest version of the library with Android 14 support.

**Q: Permission dialog doesn't show**
A: Check that your `targetSdkVersion` is set to 34 and you've included the new permission.

### Debug Logging

```kotlin
ImagePickerConfig()
.enableLog(true) // Enable debug logging
```

## Migration Checklist

- [ ] Update library to latest version
- [ ] Test on Android 14 device/emulator
- [ ] Verify both permission flows work
- [ ] Test upgrade prompts
- [ ] Ensure backward compatibility
- [ ] Update app documentation

## Best Practices

1. **Use Default Configuration**: Provides the best user experience
2. **Test Both Flows**: Test partial and full access scenarios
3. **Educate Users**: Consider showing onboarding about permission choices
4. **Graceful Degradation**: Ensure app works well with limited access
5. **Respect User Choice**: Don't force full access if partial works for your use case

## Example Implementation

```kotlin
class MainActivity : AppCompatActivity() {

private val imagePickerLauncher = registerImagePicker { images ->
handleSelectedImages(images)
}

private fun openImagePicker() {
val config = ImagePickerConfig {
mode = ImagePickerMode.MULTIPLE
limit = 10
}.enableGranularPermissions() // Android 14 support

imagePickerLauncher.launch(config)
}

private fun handleSelectedImages(images: List<Image>) {
// Handle both full and partial access scenarios
if (images.isEmpty()) {
// Show appropriate message based on permission state
showNoImagesMessage()
} else {
// Process selected images
processImages(images)
}
}
}
```

This migration ensures your app provides the best user experience on Android 14 while maintaining
full backward compatibility.
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Sun Feb 14 17:02:05 WIB 2021
#Fri Oct 03 12:04:05 SGT 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
3 changes: 3 additions & 0 deletions imagepicker/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

<!-- Android 14 (API 34) and above - Granular media permissions -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

<application>
<activity
android:name="com.esafirm.imagepicker.features.ImagePickerActivity"
Expand Down
Loading