Class SleepSample


public final class SleepSample extends SessionSample

A sleep session, optionally broken into SleepStageInterval spans.

Stage detail is not guaranteed

A session recorded by a watch usually carries stages; one inferred by a phone usually does not, and neither did iOS before version 16. Check hasStageDetail() and fall back to showing the total duration -- drawing a hypnogram from a single "asleep" span produces an empty chart that looks like a bug.

if (night.hasStageDetail()) {
    for (SleepStageInterval iv : night.getStages()) {
        drawBand(iv.getStage(), iv.getStartMillis(), iv.getEndMillis());
    }
} else {
    showTotal(night.getDurationMillis());
}
Neither phone reads sleep in this release

Sleep is available on the simulator, the desktop and the JavaScript port, and on none of the mobile ones: a sleep query is refused on iOS and Android alike, so no session of this shape ever comes back from a device. Build against it by all means -- but do not build a mobile screen around it yet.

The reason it is unfinished on iOS is worth knowing, because it shapes what finishing it will look like. HealthKit has no sleep-session object at all, only a run of overlapping category samples, so the port has to group them into sessions itself -- Apple's own convention is to split on a gap, which is what SampleQuery.setSleepSessionGapMillis(long) is there to tune. That grouping is a heuristic, which is why it belongs in the port rather than baked into the shared code.

  • Method Details

    • create

      public static SleepSample create(long startMillis, long endMillis)
      A session with no stage breakdown.
    • create

      public static SleepSample create(long startMillis, long endMillis, List<SleepStageInterval> stages)
      A session with stage detail. The list is copied defensively.
    • getStages

      public List<SleepStageInterval> getStages()
      The stage breakdown, in the order the platform reported it. Empty when no breakdown is available.
    • addStage

      public void addStage(SleepStageInterval interval)
      Appends a stage span. Used when building a session to write.
    • getStageSupport

      public SleepStageSupport getStageSupport()

      true when this session carries a real stage breakdown -- that is, at least one span classified as something more specific than "asleep", "in bed" or "unknown".

      Returns false for an empty stage list and for a list containing only SleepStage.ASLEEP_UNSPECIFIED, SleepStage.AWAKE_IN_BED and SleepStage.UNKNOWN, because none of those tell you anything a hypnogram could show. How much stage detail this session carries.

      Three answers rather than the boolean hasStageDetail(), because "has stages" collapses two cases an app has to draw differently: a session that knows only asleep-versus-awake, and one carrying a real hypnogram. Branch on this before building the UI rather than discovering it from an empty chart.

      hasStageDetail() is kept and is exactly getStageSupport() == SleepStageSupport.STAGED.

    • hasStageDetail

      public boolean hasStageDetail()
    • getDurationMillis

      public long getDurationMillis(SleepStage stage)
      The total time in stage -- the time actually covered by its spans, so two overlapping spans of the same stage count the overlap once.
    • getAsleepDurationMillis

      public long getAsleepDurationMillis()

      The total time spent asleep -- every span except SleepStage.AWAKE, SleepStage.AWAKE_IN_BED and SleepStage.OUT_OF_BED.

      Falls back to the whole session duration when no stages are present, which is the best available answer for a source that only reported "asleep from X to Y".

    • getAsleepDuration

      public Duration getAsleepDuration()

      Time asleep in this session, as a Duration.

      The millis form stays for the ports and the wire format; this is the type the rest of the framework speaks.

    • toString

      public String toString()
      Description copied from class: Object
      Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method. The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object. In other words, this method returns a string equal to the value of: getClass().getName() + '@' + Integer.toHexString(hashCode())
      Overrides:
      toString in class HealthSample