Skip to content

Commit 8c097d8

Browse files
Merge pull request #9074 from shamim-emon/fix-issue-7373
Feature: Add option to attach image from Camera
2 parents 70e7d92 + 81a6ae6 commit 8c097d8

19 files changed

Lines changed: 229 additions & 9 deletions

File tree

app-k9mail/badging/fossRelease-badging.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ uses-permission: name='android.permission.FOREGROUND_SERVICE'
1414
uses-permission: name='android.permission.FOREGROUND_SERVICE_DATA_SYNC' maxSdkVersion='33'
1515
uses-permission: name='android.permission.FOREGROUND_SERVICE_SPECIAL_USE'
1616
uses-permission: name='android.permission.SCHEDULE_EXACT_ALARM'
17+
uses-permission: name='android.permission.CAMERA'
1718
uses-permission: name='android.permission.USE_BIOMETRIC'
1819
uses-permission: name='android.permission.USE_FINGERPRINT'
1920
uses-permission: name='com.fsck.k9.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION'
@@ -84,6 +85,7 @@ property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This servic
8485
uses-library-not-required:'androidx.window.extensions'
8586
uses-library-not-required:'androidx.window.sidecar'
8687
feature-group: label=''
88+
uses-feature-not-required: name='android.hardware.camera'
8789
uses-feature-not-required: name='android.hardware.touchscreen'
8890
provides-component:'app-widget'
8991
main

app-k9mail/badging/fullRelease-badging.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ uses-permission: name='android.permission.FOREGROUND_SERVICE'
1414
uses-permission: name='android.permission.FOREGROUND_SERVICE_DATA_SYNC' maxSdkVersion='33'
1515
uses-permission: name='android.permission.FOREGROUND_SERVICE_SPECIAL_USE'
1616
uses-permission: name='android.permission.SCHEDULE_EXACT_ALARM'
17+
uses-permission: name='android.permission.CAMERA'
1718
uses-permission: name='android.permission.USE_BIOMETRIC'
1819
uses-permission: name='android.permission.USE_FINGERPRINT'
1920
uses-permission: name='com.android.vending.BILLING'
@@ -85,6 +86,7 @@ property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This servic
8586
uses-library-not-required:'androidx.window.extensions'
8687
uses-library-not-required:'androidx.window.sidecar'
8788
feature-group: label=''
89+
uses-feature-not-required: name='android.hardware.camera'
8890
uses-feature-not-required: name='android.hardware.touchscreen'
8991
provides-component:'app-widget'
9092
main
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest
3+
xmlns:android="http://schemas.android.com/apk/res/android">
4+
5+
<uses-feature android:name="android.hardware.camera" android:required="false" />
6+
<uses-permission android:name="android.permission.CAMERA"/>
7+
8+
<application android:supportsRtl="true">
9+
<provider
10+
android:name=".camera.provider.CaptureImageFileProvider"
11+
android:authorities="${applicationId}.activity"
12+
android:exported="false"
13+
android:grantUriPermissions="true"
14+
>
15+
<meta-data
16+
android:name="android.support.FILE_PROVIDER_PATHS"
17+
android:resource="@xml/capture_image_file_provider_paths"
18+
/>
19+
<meta-data
20+
android:name="de.cketti.safecontentresolver.ALLOW_INTERNAL_ACCESS"
21+
android:value="true"
22+
/>
23+
</provider>
24+
</application>
25+
26+
</manifest>

core/android/common/src/main/kotlin/app/k9mail/core/android/common/CoreCommonAndroidModule.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package app.k9mail.core.android.common
22

3+
import app.k9mail.core.android.common.camera.cameraModule
34
import app.k9mail.core.android.common.contact.contactModule
45
import app.k9mail.core.common.coreCommonModule
56
import org.koin.core.module.Module
@@ -9,4 +10,6 @@ val coreCommonAndroidModule: Module = module {
910
includes(coreCommonModule)
1011

1112
includes(contactModule)
13+
14+
includes(cameraModule)
1215
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package app.k9mail.core.android.common.camera
2+
3+
import android.Manifest.permission
4+
import android.app.Activity
5+
import android.content.Context
6+
import android.content.Intent
7+
import android.content.pm.PackageManager
8+
import android.net.Uri
9+
import android.provider.MediaStore
10+
import androidx.core.app.ActivityCompat
11+
import androidx.core.app.ActivityCompat.startActivityForResult
12+
import androidx.core.content.ContextCompat
13+
import app.k9mail.core.android.common.camera.io.CaptureImageFileWriter
14+
15+
class CameraCaptureHandler(
16+
private val captureImageFileWriter: CaptureImageFileWriter,
17+
) {
18+
19+
private lateinit var capturedImageUri: Uri
20+
21+
companion object {
22+
const val REQUEST_IMAGE_CAPTURE: Int = 6
23+
const val CAMERA_PERMISSION_REQUEST_CODE: Int = 100
24+
}
25+
26+
fun getCapturedImageUri(): Uri {
27+
if (::capturedImageUri.isInitialized) {
28+
return capturedImageUri
29+
} else {
30+
throw UninitializedPropertyAccessException("Image Uri not initialized")
31+
}
32+
}
33+
34+
fun canLaunchCamera(context: Context) =
35+
context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
36+
37+
fun openCamera(activity: Activity) {
38+
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
39+
capturedImageUri = captureImageFileWriter.getFileUri()
40+
intent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageUri)
41+
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
42+
startActivityForResult(activity, intent, REQUEST_IMAGE_CAPTURE, null)
43+
}
44+
45+
fun requestCameraPermission(activity: Activity) {
46+
ActivityCompat.requestPermissions(
47+
activity,
48+
arrayOf(permission.CAMERA),
49+
CAMERA_PERMISSION_REQUEST_CODE,
50+
)
51+
}
52+
53+
fun hasCameraPermission(context: Context): Boolean {
54+
val hasPermission = ContextCompat.checkSelfPermission(context, permission.CAMERA)
55+
return hasPermission == PackageManager.PERMISSION_GRANTED
56+
}
57+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package app.k9mail.core.android.common.camera
2+
3+
import app.k9mail.core.android.common.camera.io.CaptureImageFileWriter
4+
import org.koin.dsl.module
5+
6+
internal val cameraModule = module {
7+
single { CaptureImageFileWriter(context = get()) }
8+
single<CameraCaptureHandler> {
9+
CameraCaptureHandler(
10+
captureImageFileWriter = get(),
11+
)
12+
}
13+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package app.k9mail.core.android.common.camera.io
2+
3+
import android.content.Context
4+
import android.net.Uri
5+
import androidx.core.content.FileProvider
6+
import java.io.File
7+
8+
class CaptureImageFileWriter(private val context: Context) {
9+
10+
fun getFileUri(): Uri {
11+
val file = getCaptureImageFile()
12+
return FileProvider.getUriForFile(context, "${context.packageName}.activity", file)
13+
}
14+
15+
private fun getCaptureImageFile(): File {
16+
val fileName = "IMG_${System.currentTimeMillis()}$FILE_EXT"
17+
return File(getDirectory(), fileName)
18+
}
19+
20+
private fun getDirectory(): File {
21+
val directory = File(context.cacheDir, DIRECTORY_NAME)
22+
directory.mkdirs()
23+
24+
return directory
25+
}
26+
27+
companion object {
28+
private const val FILE_EXT = ".jpg"
29+
private const val DIRECTORY_NAME = "captureImage"
30+
}
31+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package app.k9mail.core.android.common.camera.provider
2+
3+
import androidx.core.content.FileProvider
4+
5+
class CaptureImageFileProvider : FileProvider()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<paths>
2+
<cache-path
3+
name="captureImage"
4+
path="captureImage"
5+
/>
6+
</paths>

legacy/ui/legacy/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dependencies {
1818
implementation(projects.core.featureflags)
1919
implementation(projects.core.ui.theme.api)
2020
implementation(projects.feature.launcher)
21+
implementation(projects.core.common)
2122
implementation(projects.feature.navigation.drawer.api)
2223
implementation(projects.feature.navigation.drawer.dropdown)
2324
implementation(projects.feature.navigation.drawer.siderail)

0 commit comments

Comments
 (0)