Skip to content

Releases: smileidentity/kamera-spm

kamera v1.2.1-SNAPSHOT.33

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 24 Oct 13:36

Snapshot of main at da15e119b1372fd0d69cb0d07081169b0f2590c8, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.33"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.33
React Native @smileid/kamera@1.2.1-SNAPSHOT.33, dist-tag snapshot

Changes since 1.2.0

Fixed

  • iOS: releasing a session while its preview moves off it no longer aborts the app: a
    KameraPreviewView changed its layer's session on the main thread, as it went away and as it was
    attached to a new session (the Flutter and React Native wrappers' renew() does so right after
    release()). That reconfigures the session while release() stops it on the session queue, and
    AVFoundation raised NSGenericException ("stopRunning may not be called between calls to
    beginConfiguration and commitConfiguration"), seen on a document's back capture. The view now makes
    each change on the session's own queue, one hand-over at a time: the old session lets go first,
    then the new one attaches, and a session attached meanwhile waits, the newest winning. So
    attach(session:) now lands after it returns: read previewLayer.session and its connection only
    once it has, and never assign previewLayer.session yourself. attach no longer resets the view's
    gravity to aspect-fill, which is set once when the view is made.

  • The exposure swap probes run on phones whose auto-exposure never says it has settled (Android and
    iOS).
    A swap (ExposureLong, ExposureShort) planned only where auto-exposure's own state said
    settled. The iPhone 16's front camera reported itself adjusting at every probe with a face in view,
    so both phones answered every swap unsupported (23 October 2026), which told the server the
    camera can't swap when it can. A swap now also plans where the sensor's exposure time, its ISO and
    their product each held within 0.05 stops from the frame before (one whole ISO step allowed).
    A swap's undo waits for auto-exposure to settle again, within the restore's wait, so the swap's
    other half plans from a settled exposure.

  • The Custos adapters pair the gyroscope with the accelerometer (kamera-custos,
    KameraCustos):
    beside each motion batch they chain Custos's imu events, each gyroscope
    reading paired by Custos's pairImu with the accelerometer reading nearest it, so the server can
    check that the attitude the accelerometer shows moves as the gyroscope says it turned. A gyro
    reading waits until an accelerometer reading at or after its time has come, and close() pairs
    what is left, so the SDK calls it before chaining the seal.

  • The Custos adapters hand every gyro reading to Custos to convert (kamera-custos,
    KameraCustos):
    each reading's floats go to Custos's motionReading, the one conversion every
    shim uses (Custos SPEC §6.2), instead of the adapter rounding to micro-radians itself. A reading
    Custos refuses, or one stamped before the clock began, is left out and counted in the motion
    event's refused, so the server tells a sensor reporting garbage from a phone that didn't move.
    The adapters build against Custos main again, whose motion event gained that count.

  • React Native apps that link @smileid/kamera-testing launch on iOS: kamera_spm_link.rb links KameraTesting into the app target as well as the testing pod, so Xcode embeds the dynamic framework instead of the app dying at launch with "Library not loaded: @rpath/KameraTesting.framework/KameraTesting".

  • @smileid/kamera-testing builds on iOS again with React Native 0.86: its KameraReplay module imports React, so RCTPromiseResolveBlock and RCTPromiseRejectBlock resolve and an app with the testing package linked compiles.

  • iOS: KameraReplay.install finds the kit's manifest: with no registry set, it read only the
    app bundle's manifest (fromBundle(.main)), so an app that bundles media but no manifest failed to
    install a fixture with manifestMissing. It now reads the device's fixtures as
    FixtureRegistry.fromDevice does: pushed, bundled, then the kit's own manifest with the app's media.

  • Replay media an app stages is read against the kit's manifest: with no manifest of its own,
    FixtureRegistry.fromDevice used the kit's and looked for the media inside the kit, which never
    carries it. It now reads the media from the app's own capture-fixtures/media: on iOS pushed into
    Documents or copied into the app bundle, on Android pushed into the files directory (media in the
    app's assets already merged with the kit's manifest). A folder counts once it holds every file the
    manifest names, so a stray or half-pushed one never hides complete media elsewhere.

  • ML Kit works in a minified app (Android): kamera-mlkit now ships a consumer rule keeping
    ML Kit's component registrars, which ML Kit finds by the class names in its manifest meta-data and
    R8 otherwise strips. Without it, FaceDetection.getClient() threw a NullPointerException in a
    minified partner build (seen on the Galaxy S25 Ultra, play-services-mlkit-face-detection 17.1.0).

  • Camera probes keep the sensor's response (iOS): a probe turns global tone mapping and
    low-light boost off for its frames where they're on, and the undo turns them back on, as Android
    takes probe frames without noise reduction or sharpening. Tone mapping fits a curve to each frame,
    which evens brightness out across an exposure probe, and low-light boost raises the gain by itself
    in the dark, which moves the noise with no probe commanding it. Kamera never turns tone mapping on,
    so this matters where a host or the system did.

  • Camera probes in the dark (iOS): a probe waits at least 15 frames of the camera's measured
    period as well as its 500 ms (twice that for an exposure bias), as Android does: a camera running
    slow in a dark room needs more time to apply a write than 500 ms gives it.

  • Camera probes and capture evidence on cameras whose capture results arrive late (Android): the
    Huawei GLA-LX1 (Android 11) delivered every capture result 40 to 100 ms after its image, past the
    10 ms Kamera waited, so no frame there carried readings: every probe failed and the evidence sink
    heard frames without exposure, ISO or focus. A probe frame is now cut as it arrives and judged when
    its result lands, and a frame the sink would hear without readings waits for its result (up to 8
    frames, then it goes without). Probes also wait at least 15 frames of the camera's own period, not
    only 500 ms: in a dark room that phone ran at 14 fps and its focus and zoom writes showed only after
    7 frames. There, five of six probes now apply (a 50 ms frame duration still can't, under 60 to
    80 ms exposures), where none did.

  • Camera probes: an exposure probe applies only once the sensor has moved and settled, not at
    the first frame that carries the new setting. Android needs the frame's exposure time × ISO to have
    moved at least half the commanded stops from a frame before the probe, then held within 0.05 stops
    from one frame to the next. iOS needs the same, past the bias's sync time, from each frame's EXIF.
    Exposure probes get twice the window (1 s), because auto-exposure takes longer to settle a stop
    than a lens or a zoom. The server's measurements found this on the first device crops: both phones'
    exposure steps had moved no brightness at all. A far-focus probe is held at the lens's hyperfocal
    distance, where a lens asked for infinity parks: the Galaxy S25 Ultra's front lens parked at 0.45
    diopters and never applied before.

Added

  • Prompt crops in the Custos adapters (kamera-custos, KameraCustos): when the server asks
    for prompt crops, KameraCustosCapture.askForPromptCrops() says so before the SDK chains its
    step. respond(prompt, outcome, frame) then takes the analysed frame the SDK decided a completed
    challenge on, still open. It cuts that frame's crop, seals it under role prompt-crop at the
    challenge's schedule index, and chains the response with its hash, naming the frame by the camera
    time it was chained with. sealedPromptCrops holds the packets to upload beside the probe crops.
    frame defaults to none, so existing calls are unchanged. A capture that asked refuses a
    completed response without a frame Kamera can cut (Custos SPEC §6.3 rule 10; docs/design/69, D9),
    and one whose frame Kamera's sink never chained, with Custos's CaptureChain error naming it. On
    Android, where Kamera holds a frame's evidence until its capture result lands, respond first
    suspends up to a quarter of a second for it. respond is now suspend on Android and async on
    iOS: call it from the SDK's coroutine or task, as next() is.
  • Prompt crops for Custos (native cores, for kamera-custos): KameraFrame.promptCrop()
    cuts the face of an open frame losslessly, as Custos SPEC §6.7 windows it (the region of
    interest in buffer coordinates, at least 64 and at most 512 a side), and returns a
    KameraPromptCrop of the frame's own YUV 4:2:0 samples with every stride dropped. Its
    description never prints the planes. Restricted to kamera's own adapters
    (@RestrictTo(LIBRARY_GROUP) on Android, @_spi(KameraCustos) on iOS); nothing changes for a
    host that doesn't call it (docs/design/69, D9).
  • The replay kits ship the fixture manifest: the kamera-testing AAR carries
    capture-fixtures/manifest.json as an asset and KameraTesting carries it as a resource, so
    FixtureRegistry.fromDevice finds the fixtures in any...
Read more

kamera v1.2.1-SNAPSHOT.32

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 22 Oct 21:46

Snapshot of ee51d159bd56d1dca30936a4c7799280cc3bb101 at ee51d159bd56d1dca30936a4c7799280cc3bb101, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.32"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.32
React Native @smileid/kamera@1.2.1-SNAPSHOT.32, dist-tag snapshot

Changes since 1.2.0

Fixed

  • React Native apps that link @smileid/kamera-testing launch on iOS: kamera_spm_link.rb links KameraTesting into the app target as well as the testing pod, so Xcode embeds the dynamic framework instead of the app dying at launch with "Library not loaded: @rpath/KameraTesting.framework/KameraTesting".

  • @smileid/kamera-testing builds on iOS again with React Native 0.86: its KameraReplay module imports React, so RCTPromiseResolveBlock and RCTPromiseRejectBlock resolve and an app with the testing package linked compiles.

  • iOS: KameraReplay.install finds the kit's manifest: with no registry set, it read only the
    app bundle's manifest (fromBundle(.main)), so an app that bundles media but no manifest failed to
    install a fixture with manifestMissing. It now reads the device's fixtures as
    FixtureRegistry.fromDevice does: pushed, bundled, then the kit's own manifest with the app's media.

  • Replay media an app stages is read against the kit's manifest: with no manifest of its own,
    FixtureRegistry.fromDevice used the kit's and looked for the media inside the kit, which never
    carries it. It now reads the media from the app's own capture-fixtures/media: on iOS pushed into
    Documents or copied into the app bundle, on Android pushed into the files directory (media in the
    app's assets already merged with the kit's manifest). A folder counts once it holds every file the
    manifest names, so a stray or half-pushed one never hides complete media elsewhere.

  • ML Kit works in a minified app (Android): kamera-mlkit now ships a consumer rule keeping
    ML Kit's component registrars, which ML Kit finds by the class names in its manifest meta-data and
    R8 otherwise strips. Without it, FaceDetection.getClient() threw a NullPointerException in a
    minified partner build (seen on the Galaxy S25 Ultra, play-services-mlkit-face-detection 17.1.0).

  • Camera probes keep the sensor's response (iOS): a probe turns global tone mapping and
    low-light boost off for its frames where they're on, and the undo turns them back on, as Android
    takes probe frames without noise reduction or sharpening. Tone mapping fits a curve to each frame,
    which evens brightness out across an exposure probe, and low-light boost raises the gain by itself
    in the dark, which moves the noise with no probe commanding it. Kamera never turns tone mapping on,
    so this matters where a host or the system did.

  • Camera probes in the dark (iOS): a probe waits at least 15 frames of the camera's measured
    period as well as its 500 ms (twice that for an exposure bias), as Android does: a camera running
    slow in a dark room needs more time to apply a write than 500 ms gives it.

  • Camera probes and capture evidence on cameras whose capture results arrive late (Android): the
    Huawei GLA-LX1 (Android 11) delivered every capture result 40 to 100 ms after its image, past the
    10 ms Kamera waited, so no frame there carried readings: every probe failed and the evidence sink
    heard frames without exposure, ISO or focus. A probe frame is now cut as it arrives and judged when
    its result lands, and a frame the sink would hear without readings waits for its result (up to 8
    frames, then it goes without). Probes also wait at least 15 frames of the camera's own period, not
    only 500 ms: in a dark room that phone ran at 14 fps and its focus and zoom writes showed only after
    7 frames. There, five of six probes now apply (a 50 ms frame duration still can't, under 60 to
    80 ms exposures), where none did.

  • Camera probes: an exposure probe applies only once the sensor has moved and settled, not at
    the first frame that carries the new setting. Android needs the frame's exposure time × ISO to have
    moved at least half the commanded stops from a frame before the probe, then held within 0.05 stops
    from one frame to the next. iOS needs the same, past the bias's sync time, from each frame's EXIF.
    Exposure probes get twice the window (1 s), because auto-exposure takes longer to settle a stop
    than a lens or a zoom. The server's measurements found this on the first device crops: both phones'
    exposure steps had moved no brightness at all. A far-focus probe is held at the lens's hyperfocal
    distance, where a lens asked for infinity parks: the Galaxy S25 Ultra's front lens parked at 0.45
    diopters and never applied before.

Added

  • Custos adapters run the exposure swaps: kamera-custos and KameraCustos map Custos probes
    6 and 7 to ExposureLong and ExposureShort, so a schedule's swaps reach the camera.

  • Exposure swap probes (iOS): KameraProbeKind gains exposureLong and exposureShort
    (Custos probes 6 and 7, KameraCustos only). The probe sets a custom exposure: the duration
    auto-exposure chose times or over a factor, and the ISO the other way, so the frame is as bright with
    more, or fewer, photons behind it, and the undo hands exposure back to continuous auto-exposure. A new case on KameraProbeKind breaks an exhaustive switch over it;
    it is behind @_spi(KameraCustos).

  • Exposure swap probes (Android): KameraProbeKind gains ExposureLong and ExposureShort
    (Custos probes 6 and 7, kamera-custos only). The probe turns auto-exposure off and trades the
    exposure time AE chose against its ISO by a factor, so the frame is as bright with more, or fewer,
    photons behind it: the server judges the pair by its shot noise wherever the processor holds
    brightness. Kamera now reads each capture result's exposure while the evidence sink listens, so a
    swap starts from what AE chose. A new case on KameraProbeKind breaks an exhaustive
    when over it; it is restricted to kamera's own library group.

  • Custos adapters: kamera-custos (Android) and KameraCustos (iOS) connect a Kamera session
    to a Custos capture (docs/design/69, D8). KameraCustosCapture feeds the capture from Kamera's
    evidence sink, runs the schedule's camera probes, and seals each crop to the server where it's
    taken, so the SDK uploads sealed packets and never sees the pixels. attachEvidence and
    runProbe are now the adapters' alone (@RestrictTo(LIBRARY_GROUP) on Android,
    @_spi(KameraCustos) on iOS). Each applied probe names its frame by the camera time that frame
    was chained with (Custos SPEC §6.2, kind 8, field 7), which the adapter looks up from the frames
    it chained, so the server can read the exposure each crop was taken at. Until Custos publishes,
    the adapters build only with -Pcustos.repo=DIR or KAMERA_CUSTOS_PATH.

  • Camera probes (Android and iOS): KameraSession.runProbe(KameraProbe) runs one of the
    server schedule's hidden camera-liveness probes (docs/design/69, D2–D3): focus near or far, an
    exposure step, a fixed frame duration, or a zoom. While it runs, no frame reaches the collector,
    and the evidence sink still hears every one. The first frame whose own capture result shows the
    probe applied is cropped to a set of three 128×128 luma planes: the face and a background corner at
    native resolution, and a 3×3-averaged context around the face. The next frame that still shows the
    probe gives a fourth, the same background window, so the server can check the sensor's noise is
    new in every frame (65,536 bytes in all); a probe shown by one frame only is Failed. Then the probe is undone and
    analysis resumes. It answers Applied, Unsupported (a fixed-focus lens, no such rate, a
    parameter Kamera can't express, or a replay session), Failed (nothing showed it within 500 ms),
    or NotRun (another probe or a still was running, or the session wasn't), which is not evidence.
    Host controls set during a probe (exposure, zoom, night mode, a tap) apply when it ends, and a
    still waits for it. iOS has no per-frame capture results, so a lens-position or bias probe applies
    from the sync time AVFoundation's completion reports, a frame duration from the frames' own
    intervals, and a zoom on the second frame after the write; face tracking answers unsupported.
    On Android a probe's frames are taken with NOISE_REDUCTION_MODE_OFF and EDGE_MODE_OFF wherever
    the camera lists them, so the crop keeps the sensor's own noise for the server to measure; the
    undo restores the camera's processing. iOS probes read the video data output, which never merges
    frames the way the photo pipeline does.

  • Capture evidence (Android and iOS): KameraSession.attachEvidence(KameraEvidence?) hands a
    session a sink for a signed capture record (docs/design/69, D1). While one is attached, kamera
    calls onFrame with each analysed frame's camera readings: its sensor timestamp, whether that is
    on KameraEvidenceClock, exposure, ISO, AF and AE state, and the camera id. It also runs the gyro
    and calls onMotion with batches of up to 256 readings. On iOS the clock is
    mach_continuous_time, and sample-buffer and Core Motion times are moved onto it; face tracking's
    frames report ARKit's exposure. Replay reports nothing, a sink that throws is detached (Android;
    a Swift sink can't throw), and release() detaches it. Without a sink nothing changes. The types live in
    `com.usesmileid.kamer...

Read more

kamera v1.2.1-SNAPSHOT.31

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 22 Oct 04:56

Snapshot of main at 2947cd18da6815c4312bbe4782ba83ab19a26e98, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.31"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.31
React Native @smileid/kamera@1.2.1-SNAPSHOT.31, dist-tag snapshot

Changes since 1.2.0

Fixed

  • iOS: KameraReplay.install finds the kit's manifest: with no registry set, it read only the
    app bundle's manifest (fromBundle(.main)), so an app that bundles media but no manifest failed to
    install a fixture with manifestMissing. It now reads the device's fixtures as
    FixtureRegistry.fromDevice does: pushed, bundled, then the kit's own manifest with the app's media.

  • Replay media an app stages is read against the kit's manifest: with no manifest of its own,
    FixtureRegistry.fromDevice used the kit's and looked for the media inside the kit, which never
    carries it. It now reads the media from the app's own capture-fixtures/media: on iOS pushed into
    Documents or copied into the app bundle, on Android pushed into the files directory (media in the
    app's assets already merged with the kit's manifest). A folder counts once it holds every file the
    manifest names, so a stray or half-pushed one never hides complete media elsewhere.

  • ML Kit works in a minified app (Android): kamera-mlkit now ships a consumer rule keeping
    ML Kit's component registrars, which ML Kit finds by the class names in its manifest meta-data and
    R8 otherwise strips. Without it, FaceDetection.getClient() threw a NullPointerException in a
    minified partner build (seen on the Galaxy S25 Ultra, play-services-mlkit-face-detection 17.1.0).

  • Camera probes keep the sensor's response (iOS): a probe turns global tone mapping and
    low-light boost off for its frames where they're on, and the undo turns them back on, as Android
    takes probe frames without noise reduction or sharpening. Tone mapping fits a curve to each frame,
    which evens brightness out across an exposure probe, and low-light boost raises the gain by itself
    in the dark, which moves the noise with no probe commanding it. Kamera never turns tone mapping on,
    so this matters where a host or the system did.

  • Camera probes in the dark (iOS): a probe waits at least 15 frames of the camera's measured
    period as well as its 500 ms (twice that for an exposure bias), as Android does: a camera running
    slow in a dark room needs more time to apply a write than 500 ms gives it.

  • Camera probes and capture evidence on cameras whose capture results arrive late (Android): the
    Huawei GLA-LX1 (Android 11) delivered every capture result 40 to 100 ms after its image, past the
    10 ms Kamera waited, so no frame there carried readings: every probe failed and the evidence sink
    heard frames without exposure, ISO or focus. A probe frame is now cut as it arrives and judged when
    its result lands, and a frame the sink would hear without readings waits for its result (up to 8
    frames, then it goes without). Probes also wait at least 15 frames of the camera's own period, not
    only 500 ms: in a dark room that phone ran at 14 fps and its focus and zoom writes showed only after
    7 frames. There, five of six probes now apply (a 50 ms frame duration still can't, under 60 to
    80 ms exposures), where none did.

  • Camera probes: an exposure probe applies only once the sensor has moved and settled, not at
    the first frame that carries the new setting. Android needs the frame's exposure time × ISO to have
    moved at least half the commanded stops from a frame before the probe, then held within 0.05 stops
    from one frame to the next. iOS needs the same, past the bias's sync time, from each frame's EXIF.
    Exposure probes get twice the window (1 s), because auto-exposure takes longer to settle a stop
    than a lens or a zoom. The server's measurements found this on the first device crops: both phones'
    exposure steps had moved no brightness at all. A far-focus probe is held at the lens's hyperfocal
    distance, where a lens asked for infinity parks: the Galaxy S25 Ultra's front lens parked at 0.45
    diopters and never applied before.

Added

  • Custos adapters run the exposure swaps: kamera-custos and KameraCustos map Custos probes
    6 and 7 to ExposureLong and ExposureShort, so a schedule's swaps reach the camera.

  • Exposure swap probes (iOS): KameraProbeKind gains exposureLong and exposureShort
    (Custos probes 6 and 7, KameraCustos only). The probe sets a custom exposure: the duration
    auto-exposure chose times or over a factor, and the ISO the other way, so the frame is as bright with
    more, or fewer, photons behind it, and the undo hands exposure back to continuous auto-exposure. A new case on KameraProbeKind breaks an exhaustive switch over it;
    it is behind @_spi(KameraCustos).

  • Exposure swap probes (Android): KameraProbeKind gains ExposureLong and ExposureShort
    (Custos probes 6 and 7, kamera-custos only). The probe turns auto-exposure off and trades the
    exposure time AE chose against its ISO by a factor, so the frame is as bright with more, or fewer,
    photons behind it: the server judges the pair by its shot noise wherever the processor holds
    brightness. Kamera now reads each capture result's exposure while the evidence sink listens, so a
    swap starts from what AE chose. A new case on KameraProbeKind breaks an exhaustive
    when over it; it is restricted to kamera's own library group.

  • Custos adapters: kamera-custos (Android) and KameraCustos (iOS) connect a Kamera session
    to a Custos capture (docs/design/69, D8). KameraCustosCapture feeds the capture from Kamera's
    evidence sink, runs the schedule's camera probes, and seals each crop to the server where it's
    taken, so the SDK uploads sealed packets and never sees the pixels. attachEvidence and
    runProbe are now the adapters' alone (@RestrictTo(LIBRARY_GROUP) on Android,
    @_spi(KameraCustos) on iOS). Each applied probe names its frame by the camera time that frame
    was chained with (Custos SPEC §6.2, kind 8, field 7), which the adapter looks up from the frames
    it chained, so the server can read the exposure each crop was taken at. Until Custos publishes,
    the adapters build only with -Pcustos.repo=DIR or KAMERA_CUSTOS_PATH.

  • Camera probes (Android and iOS): KameraSession.runProbe(KameraProbe) runs one of the
    server schedule's hidden camera-liveness probes (docs/design/69, D2–D3): focus near or far, an
    exposure step, a fixed frame duration, or a zoom. While it runs, no frame reaches the collector,
    and the evidence sink still hears every one. The first frame whose own capture result shows the
    probe applied is cropped to a set of three 128×128 luma planes: the face and a background corner at
    native resolution, and a 3×3-averaged context around the face. The next frame that still shows the
    probe gives a fourth, the same background window, so the server can check the sensor's noise is
    new in every frame (65,536 bytes in all); a probe shown by one frame only is Failed. Then the probe is undone and
    analysis resumes. It answers Applied, Unsupported (a fixed-focus lens, no such rate, a
    parameter Kamera can't express, or a replay session), Failed (nothing showed it within 500 ms),
    or NotRun (another probe or a still was running, or the session wasn't), which is not evidence.
    Host controls set during a probe (exposure, zoom, night mode, a tap) apply when it ends, and a
    still waits for it. iOS has no per-frame capture results, so a lens-position or bias probe applies
    from the sync time AVFoundation's completion reports, a frame duration from the frames' own
    intervals, and a zoom on the second frame after the write; face tracking answers unsupported.
    On Android a probe's frames are taken with NOISE_REDUCTION_MODE_OFF and EDGE_MODE_OFF wherever
    the camera lists them, so the crop keeps the sensor's own noise for the server to measure; the
    undo restores the camera's processing. iOS probes read the video data output, which never merges
    frames the way the photo pipeline does.

  • Capture evidence (Android and iOS): KameraSession.attachEvidence(KameraEvidence?) hands a
    session a sink for a signed capture record (docs/design/69, D1). While one is attached, kamera
    calls onFrame with each analysed frame's camera readings: its sensor timestamp, whether that is
    on KameraEvidenceClock, exposure, ISO, AF and AE state, and the camera id. It also runs the gyro
    and calls onMotion with batches of up to 256 readings. On iOS the clock is
    mach_continuous_time, and sample-buffer and Core Motion times are moved onto it; face tracking's
    frames report ARKit's exposure. Replay reports nothing, a sink that throws is detached (Android;
    a Swift sink can't throw), and release() detaches it. Without a sink nothing changes. The types live in
    com.usesmileid.kamera.integration on the native cores only: the v12 SDKs connect them to Custos
    in their native bridges, and nothing crosses to Flutter or React Native.

  • Replay: a fixture can be installed for one use case. KameraReplay.install(fixture, useCase:)
    sets the source a session of that KameraUseCase plays, beside the default install(fixture),
    so a document job replays the card for its document step and the face for its selfie. reset()
    clears them all. Core reads them through KameraReplayHooks.sessionFrameSource(useCase:), still
    compiled out of release builds....

Read more

kamera v1.2.1-SNAPSHOT.30

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 22 Oct 04:20

Snapshot of main at 8f493edaa32907b76abadfe75e63bbd2c7ebd111, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.30"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.30
React Native @smileid/kamera@1.2.1-SNAPSHOT.30, dist-tag snapshot

Changes since 1.2.0

Fixed

  • Replay media an app stages is read against the kit's manifest: with no manifest of its own,
    FixtureRegistry.fromDevice used the kit's and looked for the media inside the kit, which never
    carries it. It now reads the media from the app's own capture-fixtures/media: on iOS pushed into
    Documents or copied into the app bundle, on Android pushed into the files directory (media in the
    app's assets already merged with the kit's manifest). A folder counts once it holds every file the
    manifest names, so a stray or half-pushed one never hides complete media elsewhere.

  • ML Kit works in a minified app (Android): kamera-mlkit now ships a consumer rule keeping
    ML Kit's component registrars, which ML Kit finds by the class names in its manifest meta-data and
    R8 otherwise strips. Without it, FaceDetection.getClient() threw a NullPointerException in a
    minified partner build (seen on the Galaxy S25 Ultra, play-services-mlkit-face-detection 17.1.0).

  • Camera probes keep the sensor's response (iOS): a probe turns global tone mapping and
    low-light boost off for its frames where they're on, and the undo turns them back on, as Android
    takes probe frames without noise reduction or sharpening. Tone mapping fits a curve to each frame,
    which evens brightness out across an exposure probe, and low-light boost raises the gain by itself
    in the dark, which moves the noise with no probe commanding it. Kamera never turns tone mapping on,
    so this matters where a host or the system did.

  • Camera probes in the dark (iOS): a probe waits at least 15 frames of the camera's measured
    period as well as its 500 ms (twice that for an exposure bias), as Android does: a camera running
    slow in a dark room needs more time to apply a write than 500 ms gives it.

  • Camera probes and capture evidence on cameras whose capture results arrive late (Android): the
    Huawei GLA-LX1 (Android 11) delivered every capture result 40 to 100 ms after its image, past the
    10 ms Kamera waited, so no frame there carried readings: every probe failed and the evidence sink
    heard frames without exposure, ISO or focus. A probe frame is now cut as it arrives and judged when
    its result lands, and a frame the sink would hear without readings waits for its result (up to 8
    frames, then it goes without). Probes also wait at least 15 frames of the camera's own period, not
    only 500 ms: in a dark room that phone ran at 14 fps and its focus and zoom writes showed only after
    7 frames. There, five of six probes now apply (a 50 ms frame duration still can't, under 60 to
    80 ms exposures), where none did.

  • Camera probes: an exposure probe applies only once the sensor has moved and settled, not at
    the first frame that carries the new setting. Android needs the frame's exposure time × ISO to have
    moved at least half the commanded stops from a frame before the probe, then held within 0.05 stops
    from one frame to the next. iOS needs the same, past the bias's sync time, from each frame's EXIF.
    Exposure probes get twice the window (1 s), because auto-exposure takes longer to settle a stop
    than a lens or a zoom. The server's measurements found this on the first device crops: both phones'
    exposure steps had moved no brightness at all. A far-focus probe is held at the lens's hyperfocal
    distance, where a lens asked for infinity parks: the Galaxy S25 Ultra's front lens parked at 0.45
    diopters and never applied before.

Added

  • Custos adapters run the exposure swaps: kamera-custos and KameraCustos map Custos probes
    6 and 7 to ExposureLong and ExposureShort, so a schedule's swaps reach the camera.

  • Exposure swap probes (iOS): KameraProbeKind gains exposureLong and exposureShort
    (Custos probes 6 and 7, KameraCustos only). The probe sets a custom exposure: the duration
    auto-exposure chose times or over a factor, and the ISO the other way, so the frame is as bright with
    more, or fewer, photons behind it, and the undo hands exposure back to continuous auto-exposure. A new case on KameraProbeKind breaks an exhaustive switch over it;
    it is behind @_spi(KameraCustos).

  • Exposure swap probes (Android): KameraProbeKind gains ExposureLong and ExposureShort
    (Custos probes 6 and 7, kamera-custos only). The probe turns auto-exposure off and trades the
    exposure time AE chose against its ISO by a factor, so the frame is as bright with more, or fewer,
    photons behind it: the server judges the pair by its shot noise wherever the processor holds
    brightness. Kamera now reads each capture result's exposure while the evidence sink listens, so a
    swap starts from what AE chose. A new case on KameraProbeKind breaks an exhaustive
    when over it; it is restricted to kamera's own library group.

  • Custos adapters: kamera-custos (Android) and KameraCustos (iOS) connect a Kamera session
    to a Custos capture (docs/design/69, D8). KameraCustosCapture feeds the capture from Kamera's
    evidence sink, runs the schedule's camera probes, and seals each crop to the server where it's
    taken, so the SDK uploads sealed packets and never sees the pixels. attachEvidence and
    runProbe are now the adapters' alone (@RestrictTo(LIBRARY_GROUP) on Android,
    @_spi(KameraCustos) on iOS). Each applied probe names its frame by the camera time that frame
    was chained with (Custos SPEC §6.2, kind 8, field 7), which the adapter looks up from the frames
    it chained, so the server can read the exposure each crop was taken at. Until Custos publishes,
    the adapters build only with -Pcustos.repo=DIR or KAMERA_CUSTOS_PATH.

  • Camera probes (Android and iOS): KameraSession.runProbe(KameraProbe) runs one of the
    server schedule's hidden camera-liveness probes (docs/design/69, D2–D3): focus near or far, an
    exposure step, a fixed frame duration, or a zoom. While it runs, no frame reaches the collector,
    and the evidence sink still hears every one. The first frame whose own capture result shows the
    probe applied is cropped to a set of three 128×128 luma planes: the face and a background corner at
    native resolution, and a 3×3-averaged context around the face. The next frame that still shows the
    probe gives a fourth, the same background window, so the server can check the sensor's noise is
    new in every frame (65,536 bytes in all); a probe shown by one frame only is Failed. Then the probe is undone and
    analysis resumes. It answers Applied, Unsupported (a fixed-focus lens, no such rate, a
    parameter Kamera can't express, or a replay session), Failed (nothing showed it within 500 ms),
    or NotRun (another probe or a still was running, or the session wasn't), which is not evidence.
    Host controls set during a probe (exposure, zoom, night mode, a tap) apply when it ends, and a
    still waits for it. iOS has no per-frame capture results, so a lens-position or bias probe applies
    from the sync time AVFoundation's completion reports, a frame duration from the frames' own
    intervals, and a zoom on the second frame after the write; face tracking answers unsupported.
    On Android a probe's frames are taken with NOISE_REDUCTION_MODE_OFF and EDGE_MODE_OFF wherever
    the camera lists them, so the crop keeps the sensor's own noise for the server to measure; the
    undo restores the camera's processing. iOS probes read the video data output, which never merges
    frames the way the photo pipeline does.

  • Capture evidence (Android and iOS): KameraSession.attachEvidence(KameraEvidence?) hands a
    session a sink for a signed capture record (docs/design/69, D1). While one is attached, kamera
    calls onFrame with each analysed frame's camera readings: its sensor timestamp, whether that is
    on KameraEvidenceClock, exposure, ISO, AF and AE state, and the camera id. It also runs the gyro
    and calls onMotion with batches of up to 256 readings. On iOS the clock is
    mach_continuous_time, and sample-buffer and Core Motion times are moved onto it; face tracking's
    frames report ARKit's exposure. Replay reports nothing, a sink that throws is detached (Android;
    a Swift sink can't throw), and release() detaches it. Without a sink nothing changes. The types live in
    com.usesmileid.kamera.integration on the native cores only: the v12 SDKs connect them to Custos
    in their native bridges, and nothing crosses to Flutter or React Native.

  • Replay: a fixture can be installed for one use case. KameraReplay.install(fixture, useCase:)
    sets the source a session of that KameraUseCase plays, beside the default install(fixture),
    so a document job replays the card for its document step and the face for its selfie. reset()
    clears them all. Core reads them through KameraReplayHooks.sessionFrameSource(useCase:), still
    compiled out of release builds. The names and the useCase parameter are the same on Android and
    iOS.

Changed

  • Kamera's classes shrink and rename in a partner's release (Android): the consumer rules no
    longer keep kamera's packages whole. Nothing reaches kamera by name, and the public API is kept
    when the AAR is built, so a partner's R8 now treats kamera like its own code. In a minified app
    that...
Read more

kamera v1.2.1-SNAPSHOT.29

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 22 Oct 03:28

Snapshot of main at 874be0ceb49c2ca3689f1fe51c406db444df4a75, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.29"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.29
React Native @smileid/kamera@1.2.1-SNAPSHOT.29, dist-tag snapshot

Changes since 1.2.0

Fixed

  • ML Kit works in a minified app (Android): kamera-mlkit now ships a consumer rule keeping
    ML Kit's component registrars, which ML Kit finds by the class names in its manifest meta-data and
    R8 otherwise strips. Without it, FaceDetection.getClient() threw a NullPointerException in a
    minified partner build (seen on the Galaxy S25 Ultra, play-services-mlkit-face-detection 17.1.0).

  • Camera probes keep the sensor's response (iOS): a probe turns global tone mapping and
    low-light boost off for its frames where they're on, and the undo turns them back on, as Android
    takes probe frames without noise reduction or sharpening. Tone mapping fits a curve to each frame,
    which evens brightness out across an exposure probe, and low-light boost raises the gain by itself
    in the dark, which moves the noise with no probe commanding it. Kamera never turns tone mapping on,
    so this matters where a host or the system did.

  • Camera probes in the dark (iOS): a probe waits at least 15 frames of the camera's measured
    period as well as its 500 ms (twice that for an exposure bias), as Android does: a camera running
    slow in a dark room needs more time to apply a write than 500 ms gives it.

  • Camera probes and capture evidence on cameras whose capture results arrive late (Android): the
    Huawei GLA-LX1 (Android 11) delivered every capture result 40 to 100 ms after its image, past the
    10 ms Kamera waited, so no frame there carried readings: every probe failed and the evidence sink
    heard frames without exposure, ISO or focus. A probe frame is now cut as it arrives and judged when
    its result lands, and a frame the sink would hear without readings waits for its result (up to 8
    frames, then it goes without). Probes also wait at least 15 frames of the camera's own period, not
    only 500 ms: in a dark room that phone ran at 14 fps and its focus and zoom writes showed only after
    7 frames. There, five of six probes now apply (a 50 ms frame duration still can't, under 60 to
    80 ms exposures), where none did.

  • Camera probes: an exposure probe applies only once the sensor has moved and settled, not at
    the first frame that carries the new setting. Android needs the frame's exposure time × ISO to have
    moved at least half the commanded stops from a frame before the probe, then held within 0.05 stops
    from one frame to the next. iOS needs the same, past the bias's sync time, from each frame's EXIF.
    Exposure probes get twice the window (1 s), because auto-exposure takes longer to settle a stop
    than a lens or a zoom. The server's measurements found this on the first device crops: both phones'
    exposure steps had moved no brightness at all. A far-focus probe is held at the lens's hyperfocal
    distance, where a lens asked for infinity parks: the Galaxy S25 Ultra's front lens parked at 0.45
    diopters and never applied before.

Added

  • Custos adapters run the exposure swaps: kamera-custos and KameraCustos map Custos probes
    6 and 7 to ExposureLong and ExposureShort, so a schedule's swaps reach the camera.

  • Exposure swap probes (iOS): KameraProbeKind gains exposureLong and exposureShort
    (Custos probes 6 and 7, KameraCustos only). The probe sets a custom exposure: the duration
    auto-exposure chose times or over a factor, and the ISO the other way, so the frame is as bright with
    more, or fewer, photons behind it, and the undo hands exposure back to continuous auto-exposure. A new case on KameraProbeKind breaks an exhaustive switch over it;
    it is behind @_spi(KameraCustos).

  • Exposure swap probes (Android): KameraProbeKind gains ExposureLong and ExposureShort
    (Custos probes 6 and 7, kamera-custos only). The probe turns auto-exposure off and trades the
    exposure time AE chose against its ISO by a factor, so the frame is as bright with more, or fewer,
    photons behind it: the server judges the pair by its shot noise wherever the processor holds
    brightness. Kamera now reads each capture result's exposure while the evidence sink listens, so a
    swap starts from what AE chose. A new case on KameraProbeKind breaks an exhaustive
    when over it; it is restricted to kamera's own library group.

  • Custos adapters: kamera-custos (Android) and KameraCustos (iOS) connect a Kamera session
    to a Custos capture (docs/design/69, D8). KameraCustosCapture feeds the capture from Kamera's
    evidence sink, runs the schedule's camera probes, and seals each crop to the server where it's
    taken, so the SDK uploads sealed packets and never sees the pixels. attachEvidence and
    runProbe are now the adapters' alone (@RestrictTo(LIBRARY_GROUP) on Android,
    @_spi(KameraCustos) on iOS). Each applied probe names its frame by the camera time that frame
    was chained with (Custos SPEC §6.2, kind 8, field 7), which the adapter looks up from the frames
    it chained, so the server can read the exposure each crop was taken at. Until Custos publishes,
    the adapters build only with -Pcustos.repo=DIR or KAMERA_CUSTOS_PATH.

  • Camera probes (Android and iOS): KameraSession.runProbe(KameraProbe) runs one of the
    server schedule's hidden camera-liveness probes (docs/design/69, D2–D3): focus near or far, an
    exposure step, a fixed frame duration, or a zoom. While it runs, no frame reaches the collector,
    and the evidence sink still hears every one. The first frame whose own capture result shows the
    probe applied is cropped to a set of three 128×128 luma planes: the face and a background corner at
    native resolution, and a 3×3-averaged context around the face. The next frame that still shows the
    probe gives a fourth, the same background window, so the server can check the sensor's noise is
    new in every frame (65,536 bytes in all); a probe shown by one frame only is Failed. Then the probe is undone and
    analysis resumes. It answers Applied, Unsupported (a fixed-focus lens, no such rate, a
    parameter Kamera can't express, or a replay session), Failed (nothing showed it within 500 ms),
    or NotRun (another probe or a still was running, or the session wasn't), which is not evidence.
    Host controls set during a probe (exposure, zoom, night mode, a tap) apply when it ends, and a
    still waits for it. iOS has no per-frame capture results, so a lens-position or bias probe applies
    from the sync time AVFoundation's completion reports, a frame duration from the frames' own
    intervals, and a zoom on the second frame after the write; face tracking answers unsupported.
    On Android a probe's frames are taken with NOISE_REDUCTION_MODE_OFF and EDGE_MODE_OFF wherever
    the camera lists them, so the crop keeps the sensor's own noise for the server to measure; the
    undo restores the camera's processing. iOS probes read the video data output, which never merges
    frames the way the photo pipeline does.

  • Capture evidence (Android and iOS): KameraSession.attachEvidence(KameraEvidence?) hands a
    session a sink for a signed capture record (docs/design/69, D1). While one is attached, kamera
    calls onFrame with each analysed frame's camera readings: its sensor timestamp, whether that is
    on KameraEvidenceClock, exposure, ISO, AF and AE state, and the camera id. It also runs the gyro
    and calls onMotion with batches of up to 256 readings. On iOS the clock is
    mach_continuous_time, and sample-buffer and Core Motion times are moved onto it; face tracking's
    frames report ARKit's exposure. Replay reports nothing, a sink that throws is detached (Android;
    a Swift sink can't throw), and release() detaches it. Without a sink nothing changes. The types live in
    com.usesmileid.kamera.integration on the native cores only: the v12 SDKs connect them to Custos
    in their native bridges, and nothing crosses to Flutter or React Native.

  • Replay: a fixture can be installed for one use case. KameraReplay.install(fixture, useCase:)
    sets the source a session of that KameraUseCase plays, beside the default install(fixture),
    so a document job replays the card for its document step and the face for its selfie. reset()
    clears them all. Core reads them through KameraReplayHooks.sessionFrameSource(useCase:), still
    compiled out of release builds. The names and the useCase parameter are the same on Android and
    iOS.

Changed

  • Kamera's classes shrink and rename in a partner's release (Android): the consumer rules no
    longer keep kamera's packages whole. Nothing reaches kamera by name, and the public API is kept
    when the AAR is built, so a partner's R8 now treats kamera like its own code. In a minified app
    that runs kamera, the dex is 234,656 B smaller and no kamera class keeps a readable name (167
    did). A new kamera-android/r8check app and scripts/r8-check.sh prove a minified app streams
    frames, runs ML Kit on a kamera frame and captures a still, and the new r8-check lane runs it on
    an emulator on every Android change.

  • Breaking (probe crops): a probe crop gains a fifth plane, the face window of the next frame
    that still shows the probe (Custos SPEC §6.6), so the server measures the face's noise from frame
    to frame. KameraProbeResult.CROP_BYTES / cropBytes i...

Read more

kamera v1.2.1-SNAPSHOT.28

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 21 Oct 05:51

Snapshot of main at 260467d3523abdbd9d1bab49827fb5795aec0b19, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.28"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.28
React Native @smileid/kamera@1.2.1-SNAPSHOT.28, dist-tag snapshot

Changes since 1.2.0

Fixed

  • ML Kit works in a minified app (Android): kamera-mlkit now ships a consumer rule keeping
    ML Kit's component registrars, which ML Kit finds by the class names in its manifest meta-data and
    R8 otherwise strips. Without it, FaceDetection.getClient() threw a NullPointerException in a
    minified partner build (seen on the Galaxy S25 Ultra, play-services-mlkit-face-detection 17.1.0).

  • Camera probes keep the sensor's response (iOS): a probe turns global tone mapping and
    low-light boost off for its frames where they're on, and the undo turns them back on, as Android
    takes probe frames without noise reduction or sharpening. Tone mapping fits a curve to each frame,
    which evens brightness out across an exposure probe, and low-light boost raises the gain by itself
    in the dark, which moves the noise with no probe commanding it. Kamera never turns tone mapping on,
    so this matters where a host or the system did.

  • Camera probes in the dark (iOS): a probe waits at least 15 frames of the camera's measured
    period as well as its 500 ms (twice that for an exposure bias), as Android does: a camera running
    slow in a dark room needs more time to apply a write than 500 ms gives it.

  • Camera probes and capture evidence on cameras whose capture results arrive late (Android): the
    Huawei GLA-LX1 (Android 11) delivered every capture result 40 to 100 ms after its image, past the
    10 ms Kamera waited, so no frame there carried readings: every probe failed and the evidence sink
    heard frames without exposure, ISO or focus. A probe frame is now cut as it arrives and judged when
    its result lands, and a frame the sink would hear without readings waits for its result (up to 8
    frames, then it goes without). Probes also wait at least 15 frames of the camera's own period, not
    only 500 ms: in a dark room that phone ran at 14 fps and its focus and zoom writes showed only after
    7 frames. There, five of six probes now apply (a 50 ms frame duration still can't, under 60 to
    80 ms exposures), where none did.

  • Camera probes: an exposure probe applies only once the sensor has moved and settled, not at
    the first frame that carries the new setting. Android needs the frame's exposure time × ISO to have
    moved at least half the commanded stops from a frame before the probe, then held within 0.05 stops
    from one frame to the next. iOS needs the same, past the bias's sync time, from each frame's EXIF.
    Exposure probes get twice the window (1 s), because auto-exposure takes longer to settle a stop
    than a lens or a zoom. The server's measurements found this on the first device crops: both phones'
    exposure steps had moved no brightness at all. A far-focus probe is held at the lens's hyperfocal
    distance, where a lens asked for infinity parks: the Galaxy S25 Ultra's front lens parked at 0.45
    diopters and never applied before.

Added

  • Custos adapters run the exposure swaps: kamera-custos and KameraCustos map Custos probes
    6 and 7 to ExposureLong and ExposureShort, so a schedule's swaps reach the camera.

  • Exposure swap probes (iOS): KameraProbeKind gains exposureLong and exposureShort
    (Custos probes 6 and 7, KameraCustos only). The probe sets a custom exposure: the duration
    auto-exposure chose times or over a factor, and the ISO the other way, so the frame is as bright with
    more, or fewer, photons behind it, and the undo hands exposure back to continuous auto-exposure. A new case on KameraProbeKind breaks an exhaustive switch over it;
    it is behind @_spi(KameraCustos).

  • Exposure swap probes (Android): KameraProbeKind gains ExposureLong and ExposureShort
    (Custos probes 6 and 7, kamera-custos only). The probe turns auto-exposure off and trades the
    exposure time AE chose against its ISO by a factor, so the frame is as bright with more, or fewer,
    photons behind it: the server judges the pair by its shot noise wherever the processor holds
    brightness. Kamera now reads each capture result's exposure while the evidence sink listens, so a
    swap starts from what AE chose. A new case on KameraProbeKind breaks an exhaustive
    when over it; it is restricted to kamera's own library group.

  • Custos adapters: kamera-custos (Android) and KameraCustos (iOS) connect a Kamera session
    to a Custos capture (docs/design/69, D8). KameraCustosCapture feeds the capture from Kamera's
    evidence sink, runs the schedule's camera probes, and seals each crop to the server where it's
    taken, so the SDK uploads sealed packets and never sees the pixels. attachEvidence and
    runProbe are now the adapters' alone (@RestrictTo(LIBRARY_GROUP) on Android,
    @_spi(KameraCustos) on iOS). Each applied probe names its frame by the camera time that frame
    was chained with (Custos SPEC §6.2, kind 8, field 7), which the adapter looks up from the frames
    it chained, so the server can read the exposure each crop was taken at. Until Custos publishes,
    the adapters build only with -Pcustos.repo=DIR or KAMERA_CUSTOS_PATH.

  • Camera probes (Android and iOS): KameraSession.runProbe(KameraProbe) runs one of the
    server schedule's hidden camera-liveness probes (docs/design/69, D2–D3): focus near or far, an
    exposure step, a fixed frame duration, or a zoom. While it runs, no frame reaches the collector,
    and the evidence sink still hears every one. The first frame whose own capture result shows the
    probe applied is cropped to a set of three 128×128 luma planes: the face and a background corner at
    native resolution, and a 3×3-averaged context around the face. The next frame that still shows the
    probe gives a fourth, the same background window, so the server can check the sensor's noise is
    new in every frame (65,536 bytes in all); a probe shown by one frame only is Failed. Then the probe is undone and
    analysis resumes. It answers Applied, Unsupported (a fixed-focus lens, no such rate, a
    parameter Kamera can't express, or a replay session), Failed (nothing showed it within 500 ms),
    or NotRun (another probe or a still was running, or the session wasn't), which is not evidence.
    Host controls set during a probe (exposure, zoom, night mode, a tap) apply when it ends, and a
    still waits for it. iOS has no per-frame capture results, so a lens-position or bias probe applies
    from the sync time AVFoundation's completion reports, a frame duration from the frames' own
    intervals, and a zoom on the second frame after the write; face tracking answers unsupported.
    On Android a probe's frames are taken with NOISE_REDUCTION_MODE_OFF and EDGE_MODE_OFF wherever
    the camera lists them, so the crop keeps the sensor's own noise for the server to measure; the
    undo restores the camera's processing. iOS probes read the video data output, which never merges
    frames the way the photo pipeline does.

  • Capture evidence (Android and iOS): KameraSession.attachEvidence(KameraEvidence?) hands a
    session a sink for a signed capture record (docs/design/69, D1). While one is attached, kamera
    calls onFrame with each analysed frame's camera readings: its sensor timestamp, whether that is
    on KameraEvidenceClock, exposure, ISO, AF and AE state, and the camera id. It also runs the gyro
    and calls onMotion with batches of up to 256 readings. On iOS the clock is
    mach_continuous_time, and sample-buffer and Core Motion times are moved onto it; face tracking's
    frames report ARKit's exposure. Replay reports nothing, a sink that throws is detached (Android;
    a Swift sink can't throw), and release() detaches it. Without a sink nothing changes. The types live in
    com.usesmileid.kamera.integration on the native cores only: the v12 SDKs connect them to Custos
    in their native bridges, and nothing crosses to Flutter or React Native.

  • Replay: a fixture can be installed for one use case. KameraReplay.install(fixture, useCase:)
    sets the source a session of that KameraUseCase plays, beside the default install(fixture),
    so a document job replays the card for its document step and the face for its selfie. reset()
    clears them all. Core reads them through KameraReplayHooks.sessionFrameSource(useCase:), still
    compiled out of release builds. The names and the useCase parameter are the same on Android and
    iOS.

Changed

  • Kamera's classes shrink and rename in a partner's release (Android): the consumer rules no
    longer keep kamera's packages whole. Nothing reaches kamera by name, and the public API is kept
    when the AAR is built, so a partner's R8 now treats kamera like its own code. In a minified app
    that runs kamera, the dex is 234,656 B smaller and no kamera class keeps a readable name (167
    did). A new kamera-android/r8check app and scripts/r8-check.sh prove a minified app streams
    frames, runs ML Kit on a kamera frame and captures a still, and the new r8-check lane runs it on
    an emulator on every Android change.

  • Breaking (probe crops): a probe crop gains a fifth plane, the face window of the next frame
    that still shows the probe (Custos SPEC §6.6), so the server measures the face's noise from frame
    to frame. KameraProbeResult.CROP_BYTES / cropBytes i...

Read more

kamera v1.2.1-SNAPSHOT.27

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 18 Oct 17:40

Snapshot of main at 25dc7a4ced85c7b400ecd83ae5062fa8df2ab6ee, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.27"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.27
React Native @smileid/kamera@1.2.1-SNAPSHOT.27, dist-tag snapshot

Changes since 1.2.0

Changed

  • Testing kit (source-breaking for raw ids): the replay face and document fixtures are new
    generated recordings, and the old ones are gone. selfie-smile-v1 becomes
    selfie-neutral-smile-v2, neutral for 2.5 s and then smiling, so iOS's smile score has the
    resting mouth it compares against. head-turns-v1 becomes head-turns-v2, a 7 s loop of right,
    left and up that brings every direction back inside the enhanced selfie's 8 s timeout.
    doc-card-v1 becomes doc-id1-desk-v1, a photoreal fictional card on a desk, sized to the SDKs'
    ID-1 outline and stored as a video like the face clips. The SelfieSmile, HeadTurns and DocCard enum cases keep their names and
    point at the new ids. Code that installs a fixture by its raw id string needs the new id.

Fixed

  • Replay: a capture screen that hands over to the next no longer stops the next screen's
    replay. Sessions share the one replay source, and the next screen's session begins before the
    outgoing one is released, so the outgoing release stopped the run it no longer owned: on iOS a
    document flow's selfie step got no frames and never completed. A session now stops the source
    only while the run it began is still the one playing. Android and iOS both.
  • iOS testing kit: replay no longer crashes the app when a session restarts mid-run, as the
    document flows do between captures. A run that begin() superseded freed its frame gate below
    its starting value, which libdispatch traps on ("Semaphore object deallocated while in use").
  • Testing kit: the selfie-smile-v1 replay fixture is padded with white instead of black.
    Its dark bars made full-length uniform rows and columns, which the server rejects as an image
    issue, so an SDK's pre-upload check retook every capture and replay never completed. The face's
    size and position are unchanged.

Added

  • All four SDKs: KameraKit.deviceProfile says how capable kamera reads the device to be
    (docs/design/61): a KameraDeviceProfile with a tier of entry, standard or high (wire
    wire.deviceTier) and the signals it came from, read once per process before any camera opens.
    Android reads the Go-tier switch, the memory, the cores the phone has, the fastest core's top
    clock and, on Android 12 and later, the chip and the media performance class; iOS reads the memory
    and the model identifier. A signal kamera can't read is null and moves the tier nowhere, and
    nothing kamera does depends on the tier yet: a host records it with each capture, so the lines can
    be set from the field. On Android it's deviceProfile(context); Flutter and React Native return a
    future and a promise that never fail. The glue's shared encoder is KameraDeviceProfileWire.
  • All four SDKs: KameraMetric.AnalysisStalled(openForMs) (wire analysisStalled) reports a
    frame the host has kept in analysis for 2 s or more (KameraDefaults.analysisStallAfterMs), once
    per frame and while it is still out (docs/design/60). Until now a host analyzer that hung froze
    analysis silently: the camera delivers no fresh frame until the frame out closes, and kamera only
    reported a frame when it closed. A frame waiting in KameraFrameHub for the host's take is not in
    analysis and never counts. Each core checks once a second on a thread of its own, only while a
    frame is out and not yet reported, and only with metrics on. Breaking for exhaustive
    matches:
    a Kotlin when, Swift switch or Dart switch over KameraMetric, or a TypeScript
    switch on metric.name that ends in a never check, needs an AnalysisStalled /
    .analysisStalled / KameraAnalysisStalledMetric / KameraMetricName.AnalysisStalled case (or a
    default).

Changed

  • Flutter and React Native: the Android glue ships ML Kit's adapter alone again by default:
    kameraMlBackend defaults to mlkit, not all (docs/design/20 D9). Since 1.2.0, HMS reached
    every app, ML Kit-only ones too: it failed a Flutter release build at R8 on Cronet classes, failed
    an Expo app's manifest merge on android:allowBackup, and turned backup off in a Flutter app.
    • To keep 1.2.0's behaviour, set -PkameraMlBackend=all (or KAMERA_ML_BACKEND=all).
    • An app that opts in settles HMS's allowBackup with tools:replace, and adds
      -dontwarn org.chromium.net.** if R8 stops on the Cronet classes (docs/guide/install.md).
    • The Smile ID SDKs' Huawei packages depend on kamera-huawei themselves, so they don't need it.
  • Flutter (Android): the preview texture is a SurfaceProducer, not a SurfaceTexture. From
    Android 10 Flutter backs it with an ImageReader, which Impeller's Vulkan backend imports as it
    is; a SurfaceTexture had to be copied into Vulkan, with the raster thread waiting on the copy,
    for every preview frame. An ImageReader shows the camera's buffers as the sensor wrote them, so
    KameraPreviewView turns them by the sensor's orientation and flips a front lens's itself. The
    glue works the turn out from CameraX's description of each camera surface and sends it as the
    camera changes, showing black in between, so a lens switch never shows the last camera's frame
    turned the new camera's way (KameraTextureTransform in the Android core, for the glue). Before
    Android 10 the texture is still a SurfaceTexture, and nothing changes. A replay's frames are
    drawn into the texture already turned back, so the same transform shows them upright.

Removed

  • Android and iOS: BestFrameTracker, the best-frame ring of frames.md M2. Nothing called it on
    either core or in the SDKs. It was internal on iOS. On Android the class itself was public,
    in the com.usesmileid.kamera.internal package but outside the API lists, so it is deleted rather
    than deprecated, as a never-used symbol (the owner's exception to deprecate-first).
    Breaking (Android, source): a host that referenced
    com.usesmileid.kamera.internal.BestFrameTracker no longer compiles. Rank recent frames over the
    public scorer, frame.qualityScore(region), which stays.

kamera v1.2.1-SNAPSHOT.26

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 18 Oct 13:05

Snapshot of main at 2ac6a0de250ef3d8f6feaa5e5e16d30d7b1fe24e, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.26"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.26
React Native @smileid/kamera@1.2.1-SNAPSHOT.26, dist-tag snapshot

Changes since 1.2.0

Added

  • Testing kit: three synthetic portrait document replay fixtures, doc-greenbook-v1 (the
    South African Green Book's 320/428 page), doc-booklet-front-v1 and doc-booklet-back-v1 (a
    two-sided booklet at the default portrait 0.65), with ids on all four kits (GreenBook,
    BookletFront, BookletBack). Each is three 720x1280 frames drawn inside the SDKs' portrait
    document outline. Until now the only document fixture was the landscape doc-card-v1, so a
    portrait document flow had nothing to replay. scripts/gen_document_fixtures.py renders them.
    Source-breaking for an exhaustive match: these are new cases on the public Kotlin
    ReplayFixtureId and Swift ReplayFixtureID enums (greenBook, bookletFront,
    bookletBack on iOS), so a when or switch over every case needs the three new ones or an
    else/default branch to compile.

Fixed

  • Replay: a capture screen that hands over to the next no longer stops the next screen's
    replay. Sessions share the one replay source, and the next screen's session begins before the
    outgoing one is released, so the outgoing release stopped the run it no longer owned: on iOS a
    document flow's selfie step got no frames and never completed. A session now stops the source
    only while the run it began is still the one playing. Android and iOS both.
  • iOS testing kit: replay no longer crashes the app when a session restarts mid-run, as the
    document flows do between captures. A run that begin() superseded freed its frame gate below
    its starting value, which libdispatch traps on ("Semaphore object deallocated while in use").
  • Testing kit: the selfie-smile-v1 replay fixture is padded with white instead of black.
    Its dark bars made full-length uniform rows and columns, which the server rejects as an image
    issue, so an SDK's pre-upload check retook every capture and replay never completed. The face's
    size and position are unchanged.

Added

  • All four SDKs: KameraKit.deviceProfile says how capable kamera reads the device to be
    (docs/design/61): a KameraDeviceProfile with a tier of entry, standard or high (wire
    wire.deviceTier) and the signals it came from, read once per process before any camera opens.
    Android reads the Go-tier switch, the memory, the cores the phone has, the fastest core's top
    clock and, on Android 12 and later, the chip and the media performance class; iOS reads the memory
    and the model identifier. A signal kamera can't read is null and moves the tier nowhere, and
    nothing kamera does depends on the tier yet: a host records it with each capture, so the lines can
    be set from the field. On Android it's deviceProfile(context); Flutter and React Native return a
    future and a promise that never fail. The glue's shared encoder is KameraDeviceProfileWire.
  • All four SDKs: KameraMetric.AnalysisStalled(openForMs) (wire analysisStalled) reports a
    frame the host has kept in analysis for 2 s or more (KameraDefaults.analysisStallAfterMs), once
    per frame and while it is still out (docs/design/60). Until now a host analyzer that hung froze
    analysis silently: the camera delivers no fresh frame until the frame out closes, and kamera only
    reported a frame when it closed. A frame waiting in KameraFrameHub for the host's take is not in
    analysis and never counts. Each core checks once a second on a thread of its own, only while a
    frame is out and not yet reported, and only with metrics on. Breaking for exhaustive
    matches:
    a Kotlin when, Swift switch or Dart switch over KameraMetric, or a TypeScript
    switch on metric.name that ends in a never check, needs an AnalysisStalled /
    .analysisStalled / KameraAnalysisStalledMetric / KameraMetricName.AnalysisStalled case (or a
    default).

Changed

  • Flutter and React Native: the Android glue ships ML Kit's adapter alone again by default:
    kameraMlBackend defaults to mlkit, not all (docs/design/20 D9). Since 1.2.0, HMS reached
    every app, ML Kit-only ones too: it failed a Flutter release build at R8 on Cronet classes, failed
    an Expo app's manifest merge on android:allowBackup, and turned backup off in a Flutter app.
    • To keep 1.2.0's behaviour, set -PkameraMlBackend=all (or KAMERA_ML_BACKEND=all).
    • An app that opts in settles HMS's allowBackup with tools:replace, and adds
      -dontwarn org.chromium.net.** if R8 stops on the Cronet classes (docs/guide/install.md).
    • The Smile ID SDKs' Huawei packages depend on kamera-huawei themselves, so they don't need it.
  • Flutter (Android): the preview texture is a SurfaceProducer, not a SurfaceTexture. From
    Android 10 Flutter backs it with an ImageReader, which Impeller's Vulkan backend imports as it
    is; a SurfaceTexture had to be copied into Vulkan, with the raster thread waiting on the copy,
    for every preview frame. An ImageReader shows the camera's buffers as the sensor wrote them, so
    KameraPreviewView turns them by the sensor's orientation and flips a front lens's itself. The
    glue works the turn out from CameraX's description of each camera surface and sends it as the
    camera changes, showing black in between, so a lens switch never shows the last camera's frame
    turned the new camera's way (KameraTextureTransform in the Android core, for the glue). Before
    Android 10 the texture is still a SurfaceTexture, and nothing changes. A replay's frames are
    drawn into the texture already turned back, so the same transform shows them upright.

Removed

  • Android and iOS: BestFrameTracker, the best-frame ring of frames.md M2. Nothing called it on
    either core or in the SDKs. It was internal on iOS. On Android the class itself was public,
    in the com.usesmileid.kamera.internal package but outside the API lists, so it is deleted rather
    than deprecated, as a never-used symbol (the owner's exception to deprecate-first).
    Breaking (Android, source): a host that referenced
    com.usesmileid.kamera.internal.BestFrameTracker no longer compiles. Rank recent frames over the
    public scorer, frame.qualityScore(region), which stays.

kamera v1.2.1-SNAPSHOT.25

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 18 Oct 05:58

Snapshot of main at 555361812ce8a85fa8828d4cf43cc626e7661794, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.25"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.25
React Native @smileid/kamera@1.2.1-SNAPSHOT.25, dist-tag snapshot

Changes since 1.2.0

Fixed

  • iOS testing kit: replay no longer crashes the app when a session restarts mid-run, as the
    document flows do between captures. A run that begin() superseded freed its frame gate below
    its starting value, which libdispatch traps on ("Semaphore object deallocated while in use").
  • Testing kit: the selfie-smile-v1 replay fixture is padded with white instead of black.
    Its dark bars made full-length uniform rows and columns, which the server rejects as an image
    issue, so an SDK's pre-upload check retook every capture and replay never completed. The face's
    size and position are unchanged.

Added

  • All four SDKs: KameraKit.deviceProfile says how capable kamera reads the device to be
    (docs/design/61): a KameraDeviceProfile with a tier of entry, standard or high (wire
    wire.deviceTier) and the signals it came from, read once per process before any camera opens.
    Android reads the Go-tier switch, the memory, the cores the phone has, the fastest core's top
    clock and, on Android 12 and later, the chip and the media performance class; iOS reads the memory
    and the model identifier. A signal kamera can't read is null and moves the tier nowhere, and
    nothing kamera does depends on the tier yet: a host records it with each capture, so the lines can
    be set from the field. On Android it's deviceProfile(context); Flutter and React Native return a
    future and a promise that never fail. The glue's shared encoder is KameraDeviceProfileWire.
  • All four SDKs: KameraMetric.AnalysisStalled(openForMs) (wire analysisStalled) reports a
    frame the host has kept in analysis for 2 s or more (KameraDefaults.analysisStallAfterMs), once
    per frame and while it is still out (docs/design/60). Until now a host analyzer that hung froze
    analysis silently: the camera delivers no fresh frame until the frame out closes, and kamera only
    reported a frame when it closed. A frame waiting in KameraFrameHub for the host's take is not in
    analysis and never counts. Each core checks once a second on a thread of its own, only while a
    frame is out and not yet reported, and only with metrics on. Breaking for exhaustive
    matches:
    a Kotlin when, Swift switch or Dart switch over KameraMetric, or a TypeScript
    switch on metric.name that ends in a never check, needs an AnalysisStalled /
    .analysisStalled / KameraAnalysisStalledMetric / KameraMetricName.AnalysisStalled case (or a
    default).

Changed

  • Flutter and React Native: the Android glue ships ML Kit's adapter alone again by default:
    kameraMlBackend defaults to mlkit, not all (docs/design/20 D9). Since 1.2.0, HMS reached
    every app, ML Kit-only ones too: it failed a Flutter release build at R8 on Cronet classes, failed
    an Expo app's manifest merge on android:allowBackup, and turned backup off in a Flutter app.
    • To keep 1.2.0's behaviour, set -PkameraMlBackend=all (or KAMERA_ML_BACKEND=all).
    • An app that opts in settles HMS's allowBackup with tools:replace, and adds
      -dontwarn org.chromium.net.** if R8 stops on the Cronet classes (docs/guide/install.md).
    • The Smile ID SDKs' Huawei packages depend on kamera-huawei themselves, so they don't need it.
  • Flutter (Android): the preview texture is a SurfaceProducer, not a SurfaceTexture. From
    Android 10 Flutter backs it with an ImageReader, which Impeller's Vulkan backend imports as it
    is; a SurfaceTexture had to be copied into Vulkan, with the raster thread waiting on the copy,
    for every preview frame. An ImageReader shows the camera's buffers as the sensor wrote them, so
    KameraPreviewView turns them by the sensor's orientation and flips a front lens's itself. The
    glue works the turn out from CameraX's description of each camera surface and sends it as the
    camera changes, showing black in between, so a lens switch never shows the last camera's frame
    turned the new camera's way (KameraTextureTransform in the Android core, for the glue). Before
    Android 10 the texture is still a SurfaceTexture, and nothing changes. A replay's frames are
    drawn into the texture already turned back, so the same transform shows them upright.

Removed

  • Android and iOS: BestFrameTracker, the best-frame ring of frames.md M2. Nothing called it on
    either core or in the SDKs. It was internal on iOS. On Android the class itself was public,
    in the com.usesmileid.kamera.internal package but outside the API lists, so it is deleted rather
    than deprecated, as a never-used symbol (the owner's exception to deprecate-first).
    Breaking (Android, source): a host that referenced
    com.usesmileid.kamera.internal.BestFrameTracker no longer compiles. Rank recent frames over the
    public scorer, frame.qualityScore(region), which stays.

kamera v1.2.1-SNAPSHOT.22

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 15 Oct 18:09

Snapshot of main at 41108cff36a1487bc18352ad22d96a60ab3f0b5d, for testing only — not for production.

The current release is 1.2.0. This snapshot runs ahead of it, and the next release replaces it.

Platform This snapshot
Android com.usesmileid:kamera:1.2.1-SNAPSHOT from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS kamera-spm exact: "1.2.1-SNAPSHOT.22"
Flutter usesmileid_kamera: 1.2.1-SNAPSHOT.22
React Native @smileid/kamera@1.2.1-SNAPSHOT.22, dist-tag snapshot

Changes since 1.2.0

Added

  • All four SDKs: KameraKit.deviceProfile says how capable kamera reads the device to be
    (docs/design/61): a KameraDeviceProfile with a tier of entry, standard or high (wire
    wire.deviceTier) and the signals it came from, read once per process before any camera opens.
    Android reads the Go-tier switch, the memory, the cores the phone has, the fastest core's top
    clock and, on Android 12 and later, the chip and the media performance class; iOS reads the memory
    and the model identifier. A signal kamera can't read is null and moves the tier nowhere, and
    nothing kamera does depends on the tier yet: a host records it with each capture, so the lines can
    be set from the field. On Android it's deviceProfile(context); Flutter and React Native return a
    future and a promise that never fail. The glue's shared encoder is KameraDeviceProfileWire.
  • All four SDKs: KameraMetric.AnalysisStalled(openForMs) (wire analysisStalled) reports a
    frame the host has kept in analysis for 2 s or more (KameraDefaults.analysisStallAfterMs), once
    per frame and while it is still out (docs/design/60). Until now a host analyzer that hung froze
    analysis silently: the camera delivers no fresh frame until the frame out closes, and kamera only
    reported a frame when it closed. A frame waiting in KameraFrameHub for the host's take is not in
    analysis and never counts. Each core checks once a second on a thread of its own, only while a
    frame is out and not yet reported, and only with metrics on. Breaking for exhaustive
    matches:
    a Kotlin when, Swift switch or Dart switch over KameraMetric, or a TypeScript
    switch on metric.name that ends in a never check, needs an AnalysisStalled /
    .analysisStalled / KameraAnalysisStalledMetric / KameraMetricName.AnalysisStalled case (or a
    default).

Changed

  • Flutter and React Native: the Android glue ships ML Kit's adapter alone again by default:
    kameraMlBackend defaults to mlkit, not all (docs/design/20 D9). Since 1.2.0, HMS reached
    every app, ML Kit-only ones too: it failed a Flutter release build at R8 on Cronet classes, failed
    an Expo app's manifest merge on android:allowBackup, and turned backup off in a Flutter app.
    • To keep 1.2.0's behaviour, set -PkameraMlBackend=all (or KAMERA_ML_BACKEND=all).
    • An app that opts in settles HMS's allowBackup with tools:replace, and adds
      -dontwarn org.chromium.net.** if R8 stops on the Cronet classes (docs/guide/install.md).
    • The Smile ID SDKs' Huawei packages depend on kamera-huawei themselves, so they don't need it.
  • Flutter (Android): the preview texture is a SurfaceProducer, not a SurfaceTexture. From
    Android 10 Flutter backs it with an ImageReader, which Impeller's Vulkan backend imports as it
    is; a SurfaceTexture had to be copied into Vulkan, with the raster thread waiting on the copy,
    for every preview frame. An ImageReader shows the camera's buffers as the sensor wrote them, so
    KameraPreviewView turns them by the sensor's orientation and flips a front lens's itself. The
    glue works the turn out from CameraX's description of each camera surface and sends it as the
    camera changes, showing black in between, so a lens switch never shows the last camera's frame
    turned the new camera's way (KameraTextureTransform in the Android core, for the glue). Before
    Android 10 the texture is still a SurfaceTexture, and nothing changes. A replay's frames are
    drawn into the texture already turned back, so the same transform shows them upright.

Removed

  • Android and iOS: BestFrameTracker, the best-frame ring of frames.md M2. Nothing called it on
    either core or in the SDKs. It was internal on iOS. On Android the class itself was public,
    in the com.usesmileid.kamera.internal package but outside the API lists, so it is deleted rather
    than deprecated, as a never-used symbol (the owner's exception to deprecate-first).
    Breaking (Android, source): a host that referenced
    com.usesmileid.kamera.internal.BestFrameTracker no longer compiles. Rank recent frames over the
    public scorer, frame.qualityScore(region), which stays.