-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Fix media selection in Aztec editor #22442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b1eca0e
653484b
b532803
3c60a6b
8a4e1b6
633e533
a24aa73
609d66c
80be009
af4e5bb
4883efd
dbbb094
49c2ca4
f3379e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package org.wordpress.android.ui.posts.editor | ||
|
|
||
| import android.app.Activity | ||
| import org.wordpress.android.util.PermissionUtils | ||
| import org.wordpress.android.util.WPPermissionUtils | ||
|
|
||
| /** | ||
| * Helper object for camera-related permission handling in editor activities. | ||
| * This centralizes the camera permission logic to avoid duplication between | ||
| * EditPostActivity and GutenbergKitActivity. | ||
| */ | ||
| object EditorCameraHelper { | ||
| /** | ||
| * Checks for camera permissions and launches the camera if granted. | ||
| * If permissions are not granted, requests them from the user. | ||
| * | ||
| * @param activity The activity requesting the permission | ||
| * @param launchCamera Callback to launch the camera when permission is granted | ||
| */ | ||
| fun checkCameraPermissionAndLaunch(activity: Activity, launchCamera: () -> Unit) { | ||
| if (PermissionUtils.checkAndRequestCameraAndStoragePermissions( | ||
|
Comment on lines
+20
to
+21
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical Issue: This is likely the source of the crash reported by @dcalhoun.
Suggested fix: fun checkCameraPermissionAndLaunch(activity: Activity, launchCamera: () -> Unit) {
// Use ActivityCompat which properly handles Activity permissions
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
launchCamera()
} else {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE),
WPPermissionUtils.AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE
)
}
}Or investigate if
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a false warning. |
||
| activity, | ||
| WPPermissionUtils.AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE | ||
| ) | ||
| ) { | ||
| launchCamera() | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Handles the camera permission result in onRequestPermissionsResult. | ||
| * Should be called when requestCode matches AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE. | ||
| * | ||
| * @param requestCode The permission request code | ||
| * @param allGranted Whether all requested permissions were granted | ||
| * @param launchCamera Callback to launch the camera when permission is granted | ||
| * @return true if this helper handled the request code, false otherwise | ||
| */ | ||
| fun handlePermissionResult( | ||
| requestCode: Int, | ||
| allGranted: Boolean, | ||
| launchCamera: () -> Unit | ||
| ): Boolean { | ||
| if (requestCode == WPPermissionUtils.AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE) { | ||
| if (allGranted) { | ||
| launchCamera() | ||
| } | ||
| return true | ||
| } | ||
| return false | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,13 @@ interface EditorPhotoPickerListener { | |
| */ | ||
| interface EditorMediaActions { | ||
| fun launchCamera() | ||
|
|
||
| /** | ||
| * Checks for camera permissions and launches the camera if granted. | ||
| * If permissions are not granted, requests them from the user. | ||
| * The activity should handle the permission result and call launchCamera() when granted. | ||
| */ | ||
| fun checkCameraPermissionAndLaunch() | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -186,11 +193,31 @@ class EditorPhotoPicker( | |
| } | ||
| } | ||
|
|
||
| @Deprecated("Used only by AztecEditorFragment") | ||
| override fun onMediaToolbarButtonClicked(action: MediaToolbarAction?) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good Fix: Restoring this method implementation correctly fixes the Aztec editor regression. The previous version (from PR #22427) made this a no-op with The implementation properly handles all three media toolbar actions:
Note: Ensure this is only used by Aztec. The Gutenberg editors handle media through |
||
| // MediaPickerFragment handles its own toolbar actions through FAB and menu, | ||
| // so this method is no longer needed for the embedded picker. | ||
| // The actions are now handled through MediaPickerListener.onIconClicked() | ||
| val siteModel = siteModelProvider() | ||
| when (action) { | ||
| MediaToolbarAction.GALLERY -> { | ||
| // Show the embedded photo picker for selecting media from device | ||
| showPhotoPicker(siteModel) | ||
| } | ||
| MediaToolbarAction.CAMERA -> { | ||
| // Launch the camera to capture a photo (after checking permissions) | ||
| if (WPMediaUtils.currentUserCanUploadMedia(siteModel)) { | ||
| editorMediaActions.checkCameraPermissionAndLaunch() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code Duplication: This permission check pattern is repeated on lines 205, 255, and 262. Suggestion: Extract to a private helper method: private fun canUploadMedia(): Boolean =
WPMediaUtils.currentUserCanUploadMedia(siteModelProvider())Then use it as: if (canUploadMedia()) {
editorMediaActions.checkCameraPermissionAndLaunch()
} else {
showNoUploadPermissionSnackbar()
}This improves maintainability and reduces the chance of inconsistencies. |
||
| } else { | ||
| showNoUploadPermissionSnackbar() | ||
| } | ||
| } | ||
| MediaToolbarAction.LIBRARY -> { | ||
| // Open the WP Media Library | ||
| mediaPickerLauncher.viewWPMediaLibraryPickerForResult( | ||
| activity, | ||
| siteModel, | ||
| MediaBrowserType.EDITOR_PICKER | ||
| ) | ||
| } | ||
| null -> { /* no-op */ } | ||
| } | ||
| } | ||
|
|
||
| fun onOrientationChanged(@Orientation newOrientation: Int) { | ||
|
|
@@ -226,7 +253,7 @@ class EditorPhotoPicker( | |
| when (action) { | ||
| is MediaPickerAction.OpenCameraForPhotos -> { | ||
| if (WPMediaUtils.currentUserCanUploadMedia(siteModel)) { | ||
| editorMediaActions.launchCamera() | ||
| editorMediaActions.checkCameraPermissionAndLaunch() | ||
| } else { | ||
| showNoUploadPermissionSnackbar() | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ public class WPPermissionUtils { | |
| public static final int MEDIA_PREVIEW_PERMISSION_REQUEST_CODE = 30; | ||
| public static final int PHOTO_PICKER_MEDIA_PERMISSION_REQUEST_CODE = 40; | ||
| public static final int PHOTO_PICKER_CAMERA_PERMISSION_REQUEST_CODE = 41; | ||
| public static final int AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE = 42; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good Addition: New permission request code for Aztec editor camera functionality. Documentation Suggestion: Add a comment explaining when to use // Used when capturing photos from Aztec editor's media toolbar
public static final int AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE = 42;This helps developers understand which constant to use in different contexts. |
||
| public static final int EDITOR_MEDIA_PERMISSION_REQUEST_CODE = 60; | ||
| public static final int READER_FILE_DOWNLOAD_PERMISSION_REQUEST_CODE = 80; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| package org.wordpress.android.ui.posts.editor | ||
|
|
||
| import org.assertj.core.api.Assertions.assertThat | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
| import org.mockito.junit.MockitoJUnitRunner | ||
| import org.wordpress.android.util.WPPermissionUtils | ||
|
|
||
| @RunWith(MockitoJUnitRunner::class) | ||
| class EditorCameraHelperTest { | ||
| private var cameraLaunched = false | ||
| private val launchCamera: () -> Unit = { cameraLaunched = true } | ||
|
|
||
| @Test | ||
| fun `handlePermissionResult launches camera when requestCode matches and permissions granted`() { | ||
| // Arrange | ||
| cameraLaunched = false | ||
| val requestCode = WPPermissionUtils.AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE | ||
|
|
||
| // Act | ||
| val handled = EditorCameraHelper.handlePermissionResult( | ||
| requestCode = requestCode, | ||
| allGranted = true, | ||
| launchCamera = launchCamera | ||
| ) | ||
|
|
||
| // Assert | ||
| assertThat(handled).isTrue() | ||
| assertThat(cameraLaunched).isTrue() | ||
| } | ||
|
|
||
| @Test | ||
| fun `handlePermissionResult does not launch camera when requestCode matches but permissions denied`() { | ||
| // Arrange | ||
| cameraLaunched = false | ||
| val requestCode = WPPermissionUtils.AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE | ||
|
|
||
| // Act | ||
| val handled = EditorCameraHelper.handlePermissionResult( | ||
| requestCode = requestCode, | ||
| allGranted = false, | ||
| launchCamera = launchCamera | ||
| ) | ||
|
|
||
| // Assert | ||
| assertThat(handled).isTrue() | ||
| assertThat(cameraLaunched).isFalse() | ||
| } | ||
|
|
||
| @Test | ||
| fun `handlePermissionResult returns false when requestCode does not match`() { | ||
| // Arrange | ||
| cameraLaunched = false | ||
| val differentRequestCode = 999 | ||
|
|
||
| // Act | ||
| val handled = EditorCameraHelper.handlePermissionResult( | ||
| requestCode = differentRequestCode, | ||
| allGranted = true, | ||
| launchCamera = launchCamera | ||
| ) | ||
|
|
||
| // Assert | ||
| assertThat(handled).isFalse() | ||
| assertThat(cameraLaunched).isFalse() | ||
| } | ||
|
|
||
| @Test | ||
| fun `handlePermissionResult does not launch camera when requestCode does not match even if granted`() { | ||
| // Arrange | ||
| cameraLaunched = false | ||
| val differentRequestCode = WPPermissionUtils.EDITOR_MEDIA_PERMISSION_REQUEST_CODE | ||
|
|
||
| // Act | ||
| val handled = EditorCameraHelper.handlePermissionResult( | ||
| requestCode = differentRequestCode, | ||
| allGranted = true, | ||
| launchCamera = launchCamera | ||
| ) | ||
|
|
||
| // Assert | ||
| assertThat(handled).isFalse() | ||
| assertThat(cameraLaunched).isFalse() | ||
| } | ||
|
|
||
| @Test | ||
| fun `handlePermissionResult returns true for camera request code regardless of grant status`() { | ||
| // Arrange | ||
| val requestCode = WPPermissionUtils.AZTEC_EDITOR_CAMERA_PERMISSION_REQUEST_CODE | ||
|
|
||
| // Act & Assert - granted | ||
| val handledWhenGranted = EditorCameraHelper.handlePermissionResult( | ||
| requestCode = requestCode, | ||
| allGranted = true, | ||
| launchCamera = {} | ||
| ) | ||
| assertThat(handledWhenGranted).isTrue() | ||
|
|
||
| // Act & Assert - denied | ||
| val handledWhenDenied = EditorCameraHelper.handlePermissionResult( | ||
| requestCode = requestCode, | ||
| allGranted = false, | ||
| launchCamera = {} | ||
| ) | ||
| assertThat(handledWhenDenied).isTrue() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good Addition: This correctly handles the permission result for Aztec editor camera launches.
Minor Observation: The return value from
handlePermissionResultis not used here. This is fine since you're calling it for side effects, but consider whether other permission results in this method should also early-return if handled:This would prevent potential conflicts if multiple handlers respond to the same request code.