Repository navigation
Migrate Camera2 hardcoded snippets - #1134
Open
barbaralaw wants to merge 6 commits into
Open
barbaralaw wants to merge 6 commits into
barbaralaw wants to merge 6 commits into
Conversation
barbaralaw
marked this pull request as ready for review
September 22, 2026 21:32
kkuan2011
reviewed
Sep 23, 2026
kkuan2011
left a comment
Contributor
There was a problem hiding this comment.
Thanks Barbara! AI review flagged one issue. Can you update and send to Erik for review? Thank you!
kkuan2011
reviewed
Sep 30, 2026
kkuan2011
left a comment
Contributor
There was a problem hiding this comment.
Looks good! Minor nits and some comments to remove appcompat and to replace !! with ?.
Ready for SME review after those are addressed!
kkuan2011
reviewed
Sep 30, 2026
Rebase the Camera2 migration onto upstream main after the :camera parent module landed, keeping CameraX sources unchanged and adding the Camera2 samples plus the AppCompat, Fragment, Material, and coroutines dependencies they need.
- Use plain START_EXCLUDE (no silent + hand-written // ...) in CaptureSessionsRequests and the SurfaceView callback snippet. - Keep setRepeatingRequest commented out, matching the DAC page. - Remove all !! in the camera2 snippets: safe calls / elvis defaults, ?: return in zoomExample, checkNotNull where a non-null Size is returned. - Replace the deprecated AsyncTask.SERIAL_EXECUTOR default with a required executor parameter in openDualCamera and createDualCameraSession; the zoom example passes a caller-owned cameraExecutor placeholder. - Use ComponentActivity instead of AppCompatActivity and drop appcompat. - Replace the v.post hop with withContext(Dispatchers.IO) in the screen flash stitch-together snippet.
barbaralaw
force-pushed
the
camera2-snippet-migration
branch
from
September 30, 2026 20:39
584f960 to
2d9e8b1
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extracts the Kotlin and XML samples from eight Camera2 guides into
:cameraasregion-tagged source under
com.example.camera.snippets.camera2, so the guidescan import them instead of hardcoding them. CameraX already lives in
:cameraon
main; this PR only adds the Camera2 samples (and the extra dependenciesthey need). CameraX sources are unchanged.
44 snippets across 8 pages. 18 publish exactly what the page shows. 26 differ, every one
listed below with a reason. Line wrapping is not counted as a difference:
spotlessApplyruns before submission and rewraps long calls without changing what a reader reads.
Region tags all begin
android_camera2_; the tables drop that prefix.How to read the "why" column
// ......on its own line (omitted arguments or omitted statements). The region publishes the same ellipsis, either as a// ...line comment or as a plain[START_EXCLUDE]block that DevSite renders as..../* ... */...as the right-hand side of a typedvalthat still has a trailing// from …comment. A line comment would swallow that note, so the region wraps the ellipsis in a block comment on the same line.characteristics.get(KEY)directly (which does not compile) or uses!!. Per review, the region publishes no!!: it uses a safe call (?.), an elvis default or early return (?:), orcheckNotNull(...)where the function must return a non-null value.AsyncTask.SERIAL_EXECUTORdefault, or hopping back to the UI thread withv.postfrom a background coroutine).ListandCompletableDeferred? = nullwithout type arguments. The.md.txtexport of the same blocks is the same: no<Unit>, no<Surface>. So the sample does not compile in either form. Though the HTML file still has the type arguments<Surface>(and<Unit>,<DualCamera>,<OutputConfiguration>), they're unescaped inside the<pre>, so the parser treats them as tags — that is why both the browser and the export lose them. This is not a CSS issue; the page source has to escape those brackets (or stop writing raw<Type>in the block). The proposed migrated regions publish the type arguments the samples need. Listed again under "Live snippet fixes this surfaced".Per page
1. Camera capture sessions and requests
https://developer.android.com/media/camera/camera2/capture-sessions-requests
5 snippets, 0 match as published, 5 differ.
capture_sessions_requests_configure_session[START_EXCLUDE]blocks, 1 standalone ellipsis as a line comment; comment continued as// reasons// ...capture_sessions_requests_single_request/* ... */capture_sessions_requests_capture...kept;CaptureRequest→CaptureRequest.Buildercapture_sessions_requests_repeating_request...kept;CaptureRequest→CaptureRequest.Buildercapture_sessions_requests_interleaved_requests/* ... */createCaptureRequest()returns aCaptureRequest.Builder. The livecaptureandrepeating_requestsamples type that local asCaptureRequestand then call.build().The live repeating sample comments out
session.setRepeatingRequest(...); per review, theregion keeps that line commented out to match the page.
configure_sessionpublishes// reasonsas its own comment line so the file compiles.2. Camera lenses and capabilities
https://developer.android.com/media/camera/camera2/camera-enumeration
3 snippets, 1 match, 2 differ.
camera_enumeration_iterate_cameras// ...camera_enumeration_get_first_camera_id_facingreturn nulladded insidecatchMatching as published:
filter_cameras.The live
get_first_camera_id_facingsample is aString?function whosecatchonly logs.Kotlin requires a return on that path;
nullmatchesfirstOrNull()on the success path.3. Use multiple camera streams simultaneously
https://developer.android.com/media/camera/camera2/multiple-camera-streams-simultaneously
11 snippets, 5 match, 6 differ.
multiple_camera_streams_supported_formats?.outputFormatssafe callmultiple_camera_streams_output_sizes_format?.getOutputSizes(...)safe callmultiple_camera_streams_output_sizes_class?.getOutputSizes(...)safe callmultiple_camera_streams_maximum_output_sizecheckNotNull(...)multiple_camera_streams_preview_output_size!!on the config lookup →checkNotNull(...);"SmartSize(${long}x${short})"→"SmartSize(${long}x$short)"multiple_camera_streams_surfaceview_callback...in theSurfaceHolder.Callbackrendered by a plain[START_EXCLUDE]block around the stub overrides// ...getMaximumOutputSize()andgetPreviewOutputSize()return a non-nullSize, so a safecall would change their signatures;
checkNotNull(...)keeps them intact.Matching as published:
combined_request,hardware_level,get_preview_output_sizes,image_reader_instance,image_reader_listener.4. Screen flash
https://developer.android.com/media/camera/camera2/screen-flash-implementation-guidelines
9 snippets, 5 match, 4 differ.
screen_flash_capture_callback_ae_modeCompletableDeferred<Unit>; page rendersCompletableDeferredscreen_flash_capture_callback_convergence<Unit>type arguments;||moved to line ends past an inline commentscreen_flash_run_precapture_sequenceCompletableDeferred<Unit>screen_flash_stitch_togetherlifecycleScope.launch(Dispatchers.IO) { … v.post { … } }→lifecycleScope.launch { withContext(Dispatchers.IO) { … } … }; unusedv ->dropped; all original step comments kept, two short comments addedMatching as published:
overlay_view(XML),brightness_control,check_ae_mode,enable_disable_ae_mode,setup_repeating_request.The wrapper activity (outside every region) extends
ComponentActivity, so:cameradoesnot depend on
appcompat.5. Camera preview
https://developer.android.com/media/camera/camera2/camera-preview
2 snippets extracted, 1 match, 1 differs.
camera_preview_compute_relative_rotation!!onSENSOR_ORIENTATION→?: 0Matching as published:
surfaceview_onmeasure.Not extracted:
viewfinder_request_surface(CameraViewfinder). The page stilldocuments
CameraViewfinder,requestSurfaceAsync(), aViewfinderSurfaceRequestthat takes
CameraCharacteristics, aListenableFutureofSurface, andmarkSurfaceSafeToRelease(). Those types were deprecated and then removed; theshipping widget is
ViewfinderView, the request is width/height only, and theasync API returns a
ViewfinderSurfaceSessionthat must be closed. Publishingthe live snippet would compile only against local stand-ins, and rewriting it
to the current API is a docs change, not a migration. Recommend DevRel rework
that whole CameraViewfinder section (Kotlin, Java twin, and surrounding prose)
before it is imported.
6. HDR video capture
https://developer.android.com/media/camera/camera2/hdr-video-capture
6 snippets, 3 match, 3 differ.
hdr_video_capture_is_ten_bit_profile_supported!!in theforloop →?: return falseon the capabilities lookuphdr_video_capture_is_hlg_supportedVal→val; stray;afterreturn falsedropped; page's!!→?.getSupportedProfiles()and?.contains(...) ?: falsehdr_video_capture_setup_sessionList<Surface>andMutableList<OutputConfiguration>type argumentsMatching as published:
preview_request,record_request,encode_hdr_stream.7. Multi-camera API
https://developer.android.com/media/camera/camera2/multi-camera
6 snippets, 1 match, 5 differ.
multi_camera_find_dual_camerasMutableList<DualCamera>()→mutableListOf<DualCamera>(); type argument published; page's!!.contains(...)→?.contains(...) ?: falsemulti_camera_open_dual_cameraAsyncTask.SERIAL_EXECUTORdefault and its deprecation comment removed;executor: Executoris now requiredmulti_camera_create_dual_camera_session<Surface>type arguments published;AsyncTask.SERIAL_EXECUTORdefault and comment removed;executor: Executoris now requiredmulti_camera_find_short_long_camera_pairmaxOrNull()!!/minOrNull()!!→?: 0fdefaultsmulti_camera_zoom_examplefindShortLongCameraPair(manager)!!→?: return;createDualCameraSession(...)passesexecutor = cameraExecutor;val cameraExecutor: Executor = ... // owned by your activity / fragmentplaceholder added next to the camera manager placeholderMatching as published:
distortion_correction.MutableListhas no constructor, so the page's line cannot compile as written.The executor is now caller-owned rather than a default argument. Defaulting to a new
executor would create a thread pool per call that nothing shuts down; a required parameter
matches the page's Java
openDualCamera, which already took anExecutor, and theframework's own
openCamera(id, executor, callback).8. Camera2 Extensions API
https://developer.android.com/media/camera/camera2/extensions-api
2 snippets, both match as published:
get_extension_camera_ids,start_extension_session.This page's snippet calls
Snackbar.make(...), so:cameragainsimplementation(libs.google.android.material)and the file importscom.google.android.material.snackbar.Snackbaroutside every region — the publishedsnippet is unchanged. The alternative was a compile-only
Snackbarstand-in and no Gradlechange; that avoids pulling Views Material into the module, but it mocks an API
the page actually documents.
Not extracted
Kotlin only. Every page above except HDR video capture carries a Java twin for each of its
Kotlin blocks; those are left for the page edit that retires them. Camera preview also has a
one-line orientation formula under "Orientation calculation" that is prose, not a compilable
sample.
Camera preview's CameraViewfinder sample (
viewfinder_request_surface) is heldout of this PR on purpose; see §5. The SurfaceView onMeasure and relative-rotation
samples from the same page are in
:camera.Live snippet fixes this surfaced
.md.txtboth yieldList,CompletableDeferred?,mutableListOf()— notList<Surface>/CompletableDeferred<Unit>?/mutableListOf<OutputConfiguration>(). The HTML still contains unescaped<Surface>(etc.) inside the code block; that is markup, not Kotlin, which is why the export is empty of generics too.Val cameraCharacteristics = ...and a stray;afterreturn false.MutableList<DualCamera>()—MutableListis an interface with noconstructor.
ViewfinderViewand the request/surface APIs in the sample no longer exist on the stable viewfinder-view artifact (1.5+). The section needs a rewrite, not an import of the current Kotlin/Java fences.val captureRequest: CaptureRequest = ...then.build()—createCaptureRequest()returnsCaptureRequest.Builder.getFirstCameraIdFacingisString?but the livecatchonly logs, so the function does not compile. The region returnsnullfrom thecatch.val cameraManager: CameraManager = ...but the code below callsfindShortLongCameraPair(manager)andcreateDualCameraSession(manager, ...). The region keeps the page's naming; renaming one side is a small follow-up.Review follow-up (584f960)
[START_EXCLUDE](nosilentplus hand-written// ...) inconfigure_sessionandsurfaceview_callback.setRepeatingRequestkept commented out, matching the page.!!anywhere in the camera2 snippets (see null safety).AsyncTask.SERIAL_EXECUTORdefault replaced with a requiredexecutorparameter.ComponentActivityinstead ofAppCompatActivity;appcompatdependency removed.withContext(Dispatchers.IO)instead ofv.postinstitch_together.Region tags are unchanged by this commit.
Verification
./gradlew :camera:compileDebugKotlin— passes./gradlew :camera:lintDebug— passes./gradlew :camera:spotlessApply— run before pushing; the branch is clean afterwards