|
| 1 | +# Keep Last Frame Demo |
| 2 | + |
| 3 | +`KeepLastFrameVideo` is a demo-level player for validating the behavior of keeping the last rendered frame after natural playback completion. It does not change the base player's default completion state and does not affect other player pages globally. |
| 4 | + |
| 5 | +## Goals |
| 6 | + |
| 7 | +- After natural completion, optionally keep the current render view instead of showing the cover immediately. |
| 8 | +- Use a flag so the same page can compare keep-last-frame behavior with the default cover state. |
| 9 | +- Playback errors, manual release, and page exit still follow the normal release path. |
| 10 | +- Fullscreen and normal players copy the flag consistently. |
| 11 | + |
| 12 | +## Demo Entry |
| 13 | + |
| 14 | +Main page entry: `Keep last frame` |
| 15 | + |
| 16 | +Main classes: |
| 17 | + |
| 18 | +- `app/src/main/java/com/example/gsyvideoplayer/KeepLastFrameDemoActivity.java` |
| 19 | +- `app/src/main/java/com/example/gsyvideoplayer/video/KeepLastFrameVideo.java` |
| 20 | +- `app/src/main/res/layout/activity_keep_last_frame_demo.xml` |
| 21 | + |
| 22 | +## Basic Usage |
| 23 | + |
| 24 | +```java |
| 25 | +keepLastFrameVideo.setKeepLastFrameWhenComplete(true); |
| 26 | +``` |
| 27 | + |
| 28 | +Disable it to restore the default completion state: |
| 29 | + |
| 30 | +```java |
| 31 | +keepLastFrameVideo.setKeepLastFrameWhenComplete(false); |
| 32 | +``` |
| 33 | + |
| 34 | +The demo uses `isLastAutoCompleteRetainedSurface()` to check whether the render view was actually retained for the latest natural completion. |
| 35 | + |
| 36 | +## Implementation Notes |
| 37 | + |
| 38 | +When the flag is enabled, `KeepLastFrameVideo#onAutoCompletion()` does not call the base default completion release flow. It: |
| 39 | + |
| 40 | +- Sets state to `CURRENT_STATE_AUTO_COMPLETE`. |
| 41 | +- Keeps the current render view. |
| 42 | +- Hides the cover layer and shows completion controls. |
| 43 | +- Releases audio focus, network listener, and keep-screen-on flag. |
| 44 | +- Dispatches `onAutoComplete`. |
| 45 | + |
| 46 | +`onCompletion()`, replay, and page destroy still use the normal release flow to avoid long-lived resources. |
| 47 | + |
| 48 | +## Notes |
| 49 | + |
| 50 | +- This is a demo-level capability for validating business behavior, not a global default. |
| 51 | +- Whether the frame can be kept depends on the current render view and whether the app releases the Surface manually. |
| 52 | +- If the business must show cover, ads, or recommendations after completion, keep the default completion state. |
| 53 | +- Moving this into base components needs a full design for Surface lifecycle, cover visibility, replay, fullscreen cloning, and small-window behavior. |
| 54 | + |
| 55 | +## Regression Checklist |
| 56 | + |
| 57 | +```bash |
| 58 | +./gradlew :app:assembleDebug |
| 59 | +adb install -r app/build/outputs/apk/debug/app-debug.apk |
| 60 | +adb shell am start -n com.example.gsyvideoplayer/.MainActivity |
| 61 | +``` |
| 62 | + |
| 63 | +Manual checks: |
| 64 | + |
| 65 | +- Enter `Keep last frame`. |
| 66 | +- Enable keep-last-frame, play to natural completion, and confirm the last frame remains visible without showing the cover. |
| 67 | +- Disable keep-last-frame, replay to completion, and confirm the default cover state returns. |
| 68 | +- Replay after completion and confirm playback starts again. |
| 69 | +- Enter and exit fullscreen during playback, then wait for completion and confirm the flag still works. |
| 70 | +- Check logcat for no `FATAL EXCEPTION`, `IllegalStateException`, or Surface-related crash. |
0 commit comments