@Test
public void testGcDurationAttachment() {

  Common.Device device =
    Common.Device.newBuilder().setDeviceId(1).setFeatureLevel(AndroidVersion.VersionCodes.O).setState(Common.Device.State.ONLINE).build();
  Common.Process process = Common.Process.newBuilder().setDeviceId(1).setPid(2).setState(Common.Process.State.ALIVE).build();
  // Set up test data from range 0us-10us. Note that the proto timestamps are in nanoseconds.
  if (myUnifiedPipeline) {
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData.generateMemoryAllocStatsData(process.getPid(), 0, 0).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData.generateMemoryAllocStatsData(process.getPid(), 10, 100).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData.generateMemoryGcData(process.getPid(), 1, Memory.MemoryGcData.newBuilder()
        .setDuration(TimeUnit.MICROSECONDS.toNanos(1)).build()).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData.generateMemoryGcData(process.getPid(), 6, Memory.MemoryGcData.newBuilder()
        .setDuration(TimeUnit.MICROSECONDS.toNanos(1)).build()).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData.generateMemoryGcData(process.getPid(), 8, Memory.MemoryGcData.newBuilder()
        .setDuration(TimeUnit.MICROSECONDS.toNanos(1)).build()).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData.generateMemoryGcData(process.getPid(), 10, Memory.MemoryGcData.newBuilder()
        .setDuration(TimeUnit.MICROSECONDS.toNanos(1)).build()).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData
        .generateMemoryAllocSamplingData(process.getPid(), 1, MemoryProfilerStage.LiveAllocationSamplingMode.FULL.getValue()).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData
        .generateMemoryAllocSamplingData(process.getPid(), 5, MemoryProfilerStage.LiveAllocationSamplingMode.SAMPLED.getValue()).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData
        .generateMemoryAllocSamplingData(process.getPid(), 8, MemoryProfilerStage.LiveAllocationSamplingMode.NONE.getValue()).build());
    myTransportService.addEventToStream(
      device.getDeviceId(), ProfilersTestData
        .generateMemoryAllocSamplingData(process.getPid(), 10, MemoryProfilerStage.LiveAllocationSamplingMode.FULL.getValue()).build());
  }
  else {
    MemoryData data = MemoryData.newBuilder()
      .addAllocStatsSamples(MemoryData.AllocStatsSample.newBuilder().setTimestamp(0)
                              .setAllocStats(Memory.MemoryAllocStatsData.newBuilder().setJavaAllocationCount(0)))
      .addAllocStatsSamples(MemoryData.AllocStatsSample.newBuilder().setTimestamp(10000)
                              .setAllocStats(Memory.MemoryAllocStatsData.newBuilder().setJavaAllocationCount(100)))
      .addGcStatsSamples(MemoryData.GcStatsSample.newBuilder().setStartTime(1000).setEndTime(2000))
      .addGcStatsSamples(MemoryData.GcStatsSample.newBuilder().setStartTime(6000).setEndTime(7000))
      .addGcStatsSamples(MemoryData.GcStatsSample.newBuilder().setStartTime(8000).setEndTime(9000))
      .addGcStatsSamples(MemoryData.GcStatsSample.newBuilder().setStartTime(10000).setEndTime(11000))
      .addAllocSamplingRateEvents(AllocationSamplingRateEvent.newBuilder()
                                    .setTimestamp(1000)
                                    .setSamplingRate(MemoryAllocSamplingData.newBuilder()
                                                       .setSamplingNumInterval(
                                                         MemoryProfilerStage.LiveAllocationSamplingMode.FULL.getValue())))
      .addAllocSamplingRateEvents(AllocationSamplingRateEvent.newBuilder()
                                    .setTimestamp(5000)
                                    .setSamplingRate(MemoryAllocSamplingData.newBuilder()
                                                       .setSamplingNumInterval(
                                                         MemoryProfilerStage.LiveAllocationSamplingMode.SAMPLED.getValue())))
      .addAllocSamplingRateEvents(AllocationSamplingRateEvent.newBuilder()
                                    .setTimestamp(8000)
                                    .setSamplingRate(MemoryAllocSamplingData.newBuilder()
                                                       .setSamplingNumInterval(
                                                         MemoryProfilerStage.LiveAllocationSamplingMode.NONE.getValue())))
      .addAllocSamplingRateEvents(AllocationSamplingRateEvent.newBuilder()
                                    .setTimestamp(10000)
                                    .setSamplingRate(MemoryAllocSamplingData.newBuilder()
                                                       .setSamplingNumInterval(
                                                         MemoryProfilerStage.LiveAllocationSamplingMode.FULL.getValue())))
      .build();
    myService.setMemoryData(data);
  }
  // Set up the correct agent and session state so that the MemoryProfilerStageView can be initialized properly.
  myTransportService.setAgentStatus(Common.AgentData.newBuilder().setStatus(Common.AgentData.Status.ATTACHED).build());
  myProfilers.getSessionsManager().endCurrentSession();
  myTimer.tick(FakeTimer.ONE_SECOND_IN_NS);
  myProfilers.getSessionsManager().beginSession(device.getDeviceId(), device, process);
  myTimer.tick(FakeTimer.ONE_SECOND_IN_NS);
  myProfilers.setStage(myStage);
  // Reset the timeline so that both data range and view range stays at (0,10) on the next tick.
  myStage.getTimeline().reset(0, TimeUnit.MICROSECONDS.toNanos(10));
  myStage.getTimeline().getViewRange().set(0, 10);
  MemoryProfilerStageView view = new MemoryProfilerStageView(myProfilersView, myStage);
  // Tick a large enough time so that the renders interpolates to the final positions
  myTimer.tick(FakeTimer.ONE_SECOND_IN_NS * 10);
  DurationDataRenderer<GcDurationData> durationDataRenderer = view.getGcDurationDataRenderer();
  java.util.List<Rectangle2D.Float> renderedRegions = durationDataRenderer.getClickRegionCache();
  assertThat(renderedRegions.size()).isEqualTo(4);
  int iconWidth = StudioIcons.Profiler.Events.GARBAGE_EVENT.getIconWidth();
  int iconHeight = StudioIcons.Profiler.Events.GARBAGE_EVENT.getIconHeight();
  // Point should be attached due to start of FULL mode
  validateRegion(renderedRegions.get(0), 0.1f, 0.9f, iconWidth, iconHeight);
  // Point should be detached due to SAMPLED mode
  validateRegion(renderedRegions.get(1), 0.6f, 1f, iconWidth, iconHeight);
  // Point should be detached due to NONE mode
  validateRegion(renderedRegions.get(2), 0.8f, 1f, iconWidth, iconHeight);
  // Point should be attached due to start of FULL mode
  validateRegion(renderedRegions.get(3), 1f, 0f, iconWidth, iconHeight);
}