[API Review] Remove VideoRecordEvent#getEventType()

 Removes the EVENT_TYPE_* enum from VideoRecordEvent. The same
 functionality can be obtained using common language features such as
 `if-instanceof` in Java or `when-is` in Kotlin.

 Updated sample in documentation to explain usage.

Bug: 198241716
Test: ./gradlew camera:camera-video:connectedCheck
      && ./gradlew camera:camera-video:test
Change-Id: Ie78ed94c6d8a99cab63a5ce348a2221890498d60
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
index c8cd073..c36dcd2 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
@@ -934,7 +934,7 @@
         // Check the audio information reports state as disabled.
         val captor = ArgumentCaptor.forClass(VideoRecordEvent::class.java)
         verify(videoRecordEventListener, atLeastOnce()).accept(captor.capture())
-        assertThat(captor.value.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_STATUS)
+        assertThat(captor.value).isInstanceOf(VideoRecordEvent.Status::class.java)
         val status = captor.value as VideoRecordEvent.Status
         assertThat(status.recordingStats.audioStats.audioState)
             .isEqualTo(AudioStats.AUDIO_STATE_DISABLED)
@@ -1092,7 +1092,7 @@
         val captor = ArgumentCaptor.forClass(VideoRecordEvent::class.java)
         verify(videoRecordEventListener, atLeastOnce()).accept(captor.capture())
 
-        assertThat(captor.value.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_FINALIZE)
+        assertThat(captor.value).isInstanceOf(VideoRecordEvent.Finalize::class.java)
         val finalize = captor.value as VideoRecordEvent.Finalize
         assertThat(finalize.error).isEqualTo(ERROR_FILE_SIZE_LIMIT_REACHED)
         assertThat(file.length()).isLessThan(fileSizeLimit)
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
index 7ee8a9c..0268e19 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
@@ -101,22 +101,22 @@
     private lateinit var finalize: VideoRecordEvent.Finalize
 
     private val videoRecordEventListener = Consumer<VideoRecordEvent> {
-        when (it.eventType) {
-            VideoRecordEvent.EVENT_TYPE_START -> {
+        when (it) {
+            is VideoRecordEvent.Start -> {
                 // Recording start.
                 Log.d(TAG, "Recording start")
             }
-            VideoRecordEvent.EVENT_TYPE_FINALIZE -> {
+            is VideoRecordEvent.Finalize -> {
                 // Recording stop.
                 Log.d(TAG, "Recording finalize")
-                finalize = it as VideoRecordEvent.Finalize
+                finalize = it
                 latchForVideoSaved.countDown()
             }
-            VideoRecordEvent.EVENT_TYPE_STATUS -> {
+            is VideoRecordEvent.Status -> {
                 // Make sure the recording proceed for a while.
                 latchForVideoRecording.countDown()
             }
-            VideoRecordEvent.EVENT_TYPE_PAUSE, VideoRecordEvent.EVENT_TYPE_RESUME -> {
+            is VideoRecordEvent.Pause, is VideoRecordEvent.Resume -> {
                 // no op for this test, skip these event now.
             }
             else -> {
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java
index 2811f91..370da49 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java
@@ -23,7 +23,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
 import androidx.core.util.Consumer;
 import androidx.core.util.Preconditions;
 
@@ -38,33 +37,46 @@
  * be sent to the listener set in {@link PendingRecording#withEventListener(Executor, Consumer)}.
  *
  * <p>There are {@link Start}, {@link Finalize}, {@link Status}, {@link Pause} and {@link Resume}
- * events. The {@link #getEventType()} can be used to check what type of event is.
+ * events.
  *
- * Example: typical way to determine the event type and cast to the event class
+ * <p>Example: Below is the typical way to determine the event type and cast to the event class, if
+ * needed.
  *
  * <pre>{@code
  *
- * VideoRecordEvent videoRecordEvent = obtainVideoRecordEvent();
- * switch (videoRecordEvent.getEventType()) {
- * case VideoRecordEvent.EVENT_TYPE_START:
- *     VideoRecordEvent.Start start = (VideoRecordEvent.Start) videoRecordEvent;
- *     break;
- * case VideoRecordEvent.EVENT_TYPE_FINALIZE:
- *     VideoRecordEvent.Finalize finalize = (VideoRecordEvent.Finalize) videoRecordEvent;
- *     break;
- * case VideoRecordEvent.EVENT_TYPE_STATUS:
- *     VideoRecordEvent.Status status = (VideoRecordEvent.Status) videoRecordEvent;
- *     break;
- * case VideoRecordEvent.EVENT_TYPE_PAUSE:
- *     VideoRecordEvent.Pause pause = (VideoRecordEvent.Pause) videoRecordEvent;
- *     break;
- * case VideoRecordEvent.EVENT_TYPE_RESUME:
- *     VideoRecordEvent.Resume resume = (VideoRecordEvent.Resume) videoRecordEvent;
- *     break;
- * }
+ * ActiveRecording activeRecording = recorder.prepareRecording(outputOptions)
+ *     .withEventListener(ContextCompat.getMainExecutor(context), videoRecordEvent -> {
+ *         if (videoRecordEvent instanceof VideoRecordEvent.Start) {
+ *             // Handle the start of a new active recording
+ *             ...
+ *         } else if (videoRecordEvent instanceof VideoRecordEvent.Pause) {
+ *             // Handle the case where the active recording is paused
+ *             ...
+ *         } else if (videoRecordEvent instanceof VideoRecordEvent.Resume) {
+ *             // Handles the case where the active recording is resumed
+ *             ...
+ *         } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) {
+ *             VideoRecordEvent.Finalize finalizeEvent =
+ *                 (VideoRecordEvent.Finalize) videoRecordEvent;
+ *             // Handles a finalize event for the active recording, checking Finalize.getError()
+ *             int error = finalizeEvent.getError();
+ *             if (error != Finalize.ERROR_NONE) {
+ *                 ...
+ *             }
+ *         }
+ *
+ *         // All events, including VideoRecordEvent.Status, contain RecordingStats.
+ *         // This can be used to update the UI or track the recording duration.
+ *         RecordingStats recordingStats = videoRecordEvent.getRecordingStats();
+ *         ...
+ *     }).start();
  *
  * }</pre>
  *
+ * <p>If using Kotlin, the VideoRecordEvent class can be treated similar to a {@code sealed
+ * class}. In Kotlin, it is recommended to use a {@code when} expression rather than an {@code
+ * if}-{@code else if} chain as in the above example.
+ *
  * <p>When a video recording is requested, {@link Start} event will be reported at first and
  * {@link Finalize} event will be reported when the recording is finished. The stop reason can be
  * obtained via {@link Finalize#getError()}. {@link Finalize#ERROR_NONE} means that the video was
@@ -79,49 +91,6 @@
  */
 public abstract class VideoRecordEvent {
 
-    /**
-     * Indicates the start of recording.
-     *
-     * @see Start
-     */
-    public static final int EVENT_TYPE_START = 0;
-
-    /**
-     * Indicates the finalization of recording.
-     *
-     * @see Finalize
-     */
-    public static final int EVENT_TYPE_FINALIZE = 1;
-
-    /**
-     * The status report of the recording in progress.
-     *
-     * @see Status
-     */
-    public static final int EVENT_TYPE_STATUS = 2;
-
-    /**
-     * Indicates the pause event of recording.
-     *
-     * @see Pause
-     */
-    public static final int EVENT_TYPE_PAUSE = 3;
-
-    /**
-     * Indicates the resume event of recording.
-     *
-     * @see Resume
-     */
-    public static final int EVENT_TYPE_RESUME = 4;
-
-    /** @hide */
-    @IntDef({EVENT_TYPE_START, EVENT_TYPE_FINALIZE, EVENT_TYPE_STATUS, EVENT_TYPE_PAUSE,
-            EVENT_TYPE_RESUME})
-    @Retention(RetentionPolicy.SOURCE)
-    @RestrictTo(Scope.LIBRARY)
-    public @interface EventType {
-    }
-
     private final OutputOptions mOutputOptions;
     private final RecordingStats mRecordingStats;
 
@@ -134,15 +103,6 @@
     }
 
     /**
-     * Gets the event type.
-     *
-     * <p>Possible values are {@link #EVENT_TYPE_START}, {@link #EVENT_TYPE_FINALIZE},
-     * {@link #EVENT_TYPE_PAUSE}, {@link #EVENT_TYPE_RESUME} and {@link #EVENT_TYPE_STATUS}.
-     */
-    @EventType
-    public abstract int getEventType();
-
-    /**
      * Gets the recording status of current event.
      */
     @NonNull
@@ -176,13 +136,6 @@
         Start(@NonNull OutputOptions outputOptions, @NonNull RecordingStats recordingStats) {
             super(outputOptions, recordingStats);
         }
-
-        /** {@inheritDoc} */
-        @EventType
-        @Override
-        public int getEventType() {
-            return EVENT_TYPE_START;
-        }
     }
 
     @NonNull
@@ -324,13 +277,6 @@
             mCause = cause;
         }
 
-        /** {@inheritDoc} */
-        @EventType
-        @Override
-        public int getEventType() {
-            return EVENT_TYPE_FINALIZE;
-        }
-
         /**
          * Gets the {@link OutputResults}.
          */
@@ -389,13 +335,6 @@
         Status(@NonNull OutputOptions outputOptions, @NonNull RecordingStats recordingStats) {
             super(outputOptions, recordingStats);
         }
-
-        /** {@inheritDoc} */
-        @EventType
-        @Override
-        public int getEventType() {
-            return EVENT_TYPE_STATUS;
-        }
     }
 
     @NonNull
@@ -415,13 +354,6 @@
         Pause(@NonNull OutputOptions outputOptions, @NonNull RecordingStats recordingStats) {
             super(outputOptions, recordingStats);
         }
-
-        /** {@inheritDoc} */
-        @EventType
-        @Override
-        public int getEventType() {
-            return EVENT_TYPE_PAUSE;
-        }
     }
 
     @NonNull
@@ -441,12 +373,5 @@
         Resume(@NonNull OutputOptions outputOptions, @NonNull RecordingStats recordingStats) {
             super(outputOptions, recordingStats);
         }
-
-        /** {@inheritDoc} */
-        @EventType
-        @Override
-        public int getEventType() {
-            return EVENT_TYPE_RESUME;
-        }
     }
 }
diff --git a/camera/camera-video/src/test/java/androidx/camera/video/VideoRecordEventTest.kt b/camera/camera-video/src/test/java/androidx/camera/video/VideoRecordEventTest.kt
index 71c4d17..8fa89c7 100644
--- a/camera/camera-video/src/test/java/androidx/camera/video/VideoRecordEventTest.kt
+++ b/camera/camera-video/src/test/java/androidx/camera/video/VideoRecordEventTest.kt
@@ -47,7 +47,7 @@
             TEST_RECORDING_STATE
         )
 
-        assertThat(event.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_START)
+        assertThat(event).isInstanceOf(VideoRecordEvent.Start::class.java)
         assertThat(event.outputOptions).isEqualTo(TEST_OUTPUT_OPTION)
         assertThat(event.recordingStats).isEqualTo(TEST_RECORDING_STATE)
     }
@@ -60,7 +60,7 @@
             TEST_OUTPUT_RESULT
         )
 
-        assertThat(event.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_FINALIZE)
+        assertThat(event).isInstanceOf(VideoRecordEvent.Finalize::class.java)
         assertThat(event.outputOptions).isEqualTo(TEST_OUTPUT_OPTION)
         assertThat(event.recordingStats).isEqualTo(TEST_RECORDING_STATE)
         assertThat(event.outputResults).isEqualTo(TEST_OUTPUT_RESULT)
@@ -81,7 +81,7 @@
             cause
         )
 
-        assertThat(event.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_FINALIZE)
+        assertThat(event).isInstanceOf(VideoRecordEvent.Finalize::class.java)
         assertThat(event.outputOptions).isEqualTo(TEST_OUTPUT_OPTION)
         assertThat(event.recordingStats).isEqualTo(TEST_RECORDING_STATE)
         assertThat(event.outputResults).isEqualTo(TEST_OUTPUT_RESULT)
@@ -110,7 +110,7 @@
             TEST_RECORDING_STATE
         )
 
-        assertThat(event.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_STATUS)
+        assertThat(event).isInstanceOf(VideoRecordEvent.Status::class.java)
         assertThat(event.outputOptions).isEqualTo(TEST_OUTPUT_OPTION)
         assertThat(event.recordingStats).isEqualTo(TEST_RECORDING_STATE)
     }
@@ -122,7 +122,7 @@
             TEST_RECORDING_STATE
         )
 
-        assertThat(event.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_PAUSE)
+        assertThat(event).isInstanceOf(VideoRecordEvent.Pause::class.java)
         assertThat(event.outputOptions).isEqualTo(TEST_OUTPUT_OPTION)
         assertThat(event.recordingStats).isEqualTo(TEST_RECORDING_STATE)
     }
@@ -134,7 +134,7 @@
             TEST_RECORDING_STATE
         )
 
-        assertThat(event.eventType).isEqualTo(VideoRecordEvent.EVENT_TYPE_RESUME)
+        assertThat(event).isInstanceOf(VideoRecordEvent.Resume::class.java)
         assertThat(event.outputOptions).isEqualTo(TEST_OUTPUT_OPTION)
         assertThat(event.recordingStats).isEqualTo(TEST_RECORDING_STATE)
     }
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index 3c8a8f7a..7a5351a 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -477,60 +477,54 @@
     private final Consumer<VideoRecordEvent> mVideoRecordEventListener = event -> {
         updateRecordingStats(event.getRecordingStats());
 
-        switch (event.getEventType()) {
-            case VideoRecordEvent.EVENT_TYPE_FINALIZE:
-                VideoRecordEvent.Finalize finalize = (VideoRecordEvent.Finalize) event;
+        if (event instanceof VideoRecordEvent.Finalize) {
+            VideoRecordEvent.Finalize finalize = (VideoRecordEvent.Finalize) event;
 
-                switch (finalize.getError()) {
-                    case ERROR_NONE:
-                    case ERROR_FILE_SIZE_LIMIT_REACHED:
-                    case ERROR_INSUFFICIENT_DISK:
-                    case ERROR_SOURCE_INACTIVE:
-                        Uri uri = finalize.getOutputResults().getOutputUri();
-                        OutputOptions outputOptions = finalize.getOutputOptions();
-                        String msg;
-                        String videoFilePath;
-                        if (outputOptions instanceof MediaStoreOutputOptions) {
-                            msg = "Saved uri " + uri;
-                            videoFilePath = getAbsolutePathFromUri(
-                                    getApplicationContext().getContentResolver(),
-                                    uri
-                            );
-                            // For OutputOptionsType is OutputOptions.OPTIONS_TYPE_MEDIA_STORE,
-                            // the Photo/Gallery apps on devices (API Level < Q) sometimes will
-                            // not show the video files saved in MediaStore, suggest to call
-                            // scanFile still to force scan the media file.
-                            // scanVideoOutputFile(new File(videoFilePath));
-                        } else if (outputOptions instanceof FileOutputOptions) {
-                            videoFilePath = ((FileOutputOptions) outputOptions)
-                                    .getFile().getAbsolutePath();
-                            msg = "Saved video file: " + videoFilePath;
-                            scanVideoOutputFile(new File(videoFilePath));
-                        } else {
-                            throw new AssertionError("Unknown or unsupported OutputOptions type: "
-                                    + outputOptions.getClass().getSimpleName());
-                        }
-                        // The video file path is used in tracing e2e test log. Don't remove it.
-                        Log.d(TAG, "Saved video file: " + videoFilePath);
+            switch (finalize.getError()) {
+                case ERROR_NONE:
+                case ERROR_FILE_SIZE_LIMIT_REACHED:
+                case ERROR_INSUFFICIENT_DISK:
+                case ERROR_SOURCE_INACTIVE:
+                    Uri uri = finalize.getOutputResults().getOutputUri();
+                    OutputOptions outputOptions = finalize.getOutputOptions();
+                    String msg;
+                    String videoFilePath;
+                    if (outputOptions instanceof MediaStoreOutputOptions) {
+                        msg = "Saved uri " + uri;
+                        videoFilePath = getAbsolutePathFromUri(
+                                getApplicationContext().getContentResolver(),
+                                uri
+                        );
+                        // For OutputOptionsType is OutputOptions.OPTIONS_TYPE_MEDIA_STORE,
+                        // the Photo/Gallery apps on devices (API Level < Q) sometimes will
+                        // not show the video files saved in MediaStore, suggest to call
+                        // scanFile still to force scan the media file.
+                        // scanVideoOutputFile(new File(videoFilePath));
+                    } else if (outputOptions instanceof FileOutputOptions) {
+                        videoFilePath = ((FileOutputOptions) outputOptions)
+                                .getFile().getAbsolutePath();
+                        msg = "Saved video file: " + videoFilePath;
+                        scanVideoOutputFile(new File(videoFilePath));
+                    } else {
+                        throw new AssertionError("Unknown or unsupported OutputOptions type: "
+                                + outputOptions.getClass().getSimpleName());
+                    }
+                    // The video file path is used in tracing e2e test log. Don't remove it.
+                    Log.d(TAG, "Saved video file: " + videoFilePath);
 
-                        if (finalize.getError() != ERROR_NONE) {
-                            msg += " with code (" + finalize.getError() + ")";
-                        }
-                        Log.d(TAG, msg, finalize.getCause());
-                        Toast.makeText(CameraXActivity.this, msg, Toast.LENGTH_LONG).show();
-                        break;
-                    default:
-                        String errMsg = "Video capture failed by (" + finalize.getError() + "): "
-                                + finalize.getCause();
-                        Log.e(TAG, errMsg, finalize.getCause());
-                        Toast.makeText(CameraXActivity.this, errMsg, Toast.LENGTH_LONG).show();
-                }
-                mRecordUi.setState(RecordUi.State.IDLE);
-                break;
-
-            default:
-                // No-op
-                break;
+                    if (finalize.getError() != ERROR_NONE) {
+                        msg += " with code (" + finalize.getError() + ")";
+                    }
+                    Log.d(TAG, msg, finalize.getCause());
+                    Toast.makeText(CameraXActivity.this, msg, Toast.LENGTH_LONG).show();
+                    break;
+                default:
+                    String errMsg = "Video capture failed by (" + finalize.getError() + "): "
+                            + finalize.getCause();
+                    Log.e(TAG, errMsg, finalize.getCause());
+                    Toast.makeText(CameraXActivity.this, errMsg, Toast.LENGTH_LONG).show();
+            }
+            mRecordUi.setState(RecordUi.State.IDLE);
         }
     };