diff --git a/asg_client/app/src/main/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandler.java b/asg_client/app/src/main/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandler.java index 4e5e66dae8..2c97890861 100644 --- a/asg_client/app/src/main/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandler.java +++ b/asg_client/app/src/main/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandler.java @@ -351,15 +351,15 @@ private boolean handleTakePhoto(JSONObject data) { return false; } - // ARCHIVAL CAPTURE: a save-only request (no upload target) has no delivery leg — + // ARCHIVAL CAPTURE: a save-only request (no delivery target) has no delivery leg — // no webhook upload, no BLE transfer — so there is nothing for the single-flight // photo-job gate to protect. Route it down the button-photo path: camera-queue // serialized, no CAMERA_BUSY, so SDK callers can burst-save to the gallery and // pull the files later over WiFi sync (each stamped with its requestId). - // transferMethod is deliberately not consulted: it is always "auto" in practice - // and the phone app always supplies a webhookUrl, so this shape is only ever - // produced by direct BT-SDK callers that want exactly this behavior. - if (save && webhookUrl.isEmpty()) { + // A request carrying a bleImgId DOES have a delivery leg (BLE to the phone) and + // must go down the normal pipeline even with save=true and no webhookUrl: that + // shape is phone-delivery with a kept gallery copy, not an archival capture. + if (save && webhookUrl.isEmpty() && bleImgId.isEmpty()) { Log.i( TAG, "PHOTO PIPELINE [ASG 3/3] Local-save capture (no upload target)" diff --git a/asg_client/app/src/test/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandlerTransferMethodTest.java b/asg_client/app/src/test/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandlerTransferMethodTest.java index 9633bc2920..05c6774352 100644 --- a/asg_client/app/src/test/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandlerTransferMethodTest.java +++ b/asg_client/app/src/test/java/com/mentra/asg_client/service/core/handlers/PhotoCommandHandlerTransferMethodTest.java @@ -7,6 +7,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -150,4 +151,82 @@ public void takePhoto_invalidTransferMethod_isRejected() throws Exception { verify(captureService) .sendPhotoErrorResponse(eq("req-1"), eq("INVALID_TRANSFER_METHOD"), anyString()); } + + @Test + public void takePhoto_saveWithBleImgIdAndNoWebhook_ridesBleTransfer() throws Exception { + when(captureService.takePhotoForBleTransfer( + anyString(), + anyString(), + anyString(), + anyBoolean(), + anyString(), + anyString(), + anyBoolean(), + anyBoolean(), + nullable(Long.class), + nullable(Integer.class), + any(PhotoCaptureSettings.class))) + .thenReturn(true); + JSONObject data = + takePhotoData() + .put("webhookUrl", "") + .put("save", true) + .put("transferMethod", "ble"); + + assertThat(handler.handleCommand("take_photo", data)).isTrue(); + verify(captureService) + .takePhotoForBleTransfer( + anyString(), + eq("req-1"), + eq("ble-1"), + eq(true), + eq("medium"), + eq("photo"), + eq(true), + eq(true), + nullable(Long.class), + nullable(Integer.class), + any(PhotoCaptureSettings.class)); + verify(captureService, never()) + .takePhotoForLocalSave( + anyString(), + anyString(), + anyString(), + anyString(), + anyBoolean(), + anyBoolean(), + nullable(Long.class), + nullable(Integer.class), + any(PhotoCaptureSettings.class)); + } + + @Test + public void takePhoto_saveWithoutBleImgIdOrWebhook_staysLocalSaveCapture() throws Exception { + when(captureService.takePhotoForLocalSave( + anyString(), + anyString(), + anyString(), + anyString(), + anyBoolean(), + anyBoolean(), + nullable(Long.class), + nullable(Integer.class), + any(PhotoCaptureSettings.class))) + .thenReturn(true); + JSONObject data = + takePhotoData().put("webhookUrl", "").put("bleImgId", "").put("save", true); + + assertThat(handler.handleCommand("take_photo", data)).isTrue(); + verify(captureService) + .takePhotoForLocalSave( + anyString(), + eq("req-1"), + eq("medium"), + eq("photo"), + eq(true), + eq(true), + nullable(Long.class), + nullable(Integer.class), + any(PhotoCaptureSettings.class)); + } }