Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@tuuhin
Copy link
Owner

@tuuhin tuuhin commented Nov 2, 2025

This pull request introduces a comprehensive set of enhancements, critical bug fixes, and significant refactoring across the application. Key areas of improvement include performance optimization in the UI and data layers and a major expansion of test coverage for few of the data layer components

Key Highlights

🚀 Performance & UI Enhancements

  • Lazy Loading in UI: Implemented lazy reads for timer text and track data in Recorder, Player and Editor significantly reducing re composition counts
  • Optimized Player Controls: The PlayerTrackSlider2 now use new Compose API's for a non-recomposing slider experience.
  • Background Threading: Moved media extraction to custom HandlerThread to reduce main thread pressure.
  • Test coverage: Included instrumented test for few of the modules in data layer

🐛 Bug Fixes & Stability

  • Splash Screen Crash: Fixed a NullPointerException in splash screen, there was issue with splash.iconView was not ready before animation API are called
  • Player State Logic: Corrected Player flows included a buffering state in playing flow, and track data flow responds to timeline changes.
  • Database Timestamps: Fixed a logical bug in LocalDateTimeConvertor that used the system time zone instead of UTC. Made a database migration has been added to correct existing timestamps.
  • Recording & Playback: Ensured coroutine context is active during audio reads in AudioRecordAmplitudeReader, alongside corrected buffer size calculation for stereo mode.

🛠️ Refactoring & Code Quality

  • Dependency Management: Updated project dependencies to the latest versions and cleaned up resources Included testing runtime dependencies that provides the Custom test runner for hilt to work
  • •Service & State Management: Refactored RecorderServiceBinderImpl and MediaControleller to use flows instead of nullable types for a more robust, observable service.
  • DI & Player Architecture: Reorganized DI modules, creating PlayerCommonModule for shared ExoPlayer configurations.
  • Recording Formats: The RecordFormats has been refactored into an Enum class to better manage recorder initializations, removing the old RecordEncoderAndFormat

🧪 Comprehensive Test Coverage

  • Included testing-runtime Module: Created a dedicated module to provide HiltTestRunner and core testing dependencies for Android tests.
  • Database Migration Tests: Added DBMigrationsTests to validate the UTC timestamp correction.
  • Datastore Tests: Implemented tests for Datastore using a TestDatastoreProvider which provide ensure isolation from the original files

This update significantly improves application performance, reliability, and maintainability. By enhancing threading, refactoring service logic, and expanding test coverage

tuuhin added 25 commits October 24, 2025 19:50
This module will provide HiltTestRunner.kt required for hilt based android test
build.gradle.kts in testing-runtime is normally defined without any custom plugins as we dont need the overhead of library configuration
Updated few versions in libs.versions.toml
Included hilt test and hilt compiler for kspAndroidTest in ConfigureHiltPlugin.kt
Again included some more core dependencies like kotlin test in ConfigureAndroidLibraryPlugin.kt
Corrected the logic to save bookmarks and also file deletion when coroutine is cancelled
Included testing-runtime as android test impl for hilt test
BookmarksTestModule.kt provides the test module
BookMarksToCsvConvertorTest.kt , android test for creating bookmarks from list of audio bookmarks
ExportURIProvider.kt provides the directory and getFileUri methods for main and test implementations
Created room in memory db for testing in RecorderDataBase.kt and DatabaseTestModule.kt as di test module
RecordingsBookmarkDao.kt included option to delete all the entries this is used in testing part
RecordingsBookmarkProviderTest.kt tests the methods and check is everything is expected as in RecordingBookMarkProviderImpl.kt where unwanted with context block is removed and cancellation exception throw is added
Included turbine dependency to test flows
RecordingsCategoryProviderImpl.kt included CancellationException in all methods which is thrown to the parent coroutine
For update it first checks if we already have a category with the given id if not Resource.Error is returned, RecordingsBookmarkProviderTest.kt tests the following methods for errors and correct flow
Again method to delete all entries method included in RecordingCategoryDao.kt for testing purpose
Included turbine dependency in ConfigureAndroidLibraryPlugin.kt so no need to mention it in dependencies block
In bookmarks test the clear entries should happen in teardown
LocalDateTimeConvertors.kt were using system timezone to convert local datetime to instant which is wrong as timezone can change we need to use a constant like UTC
So in DBMigrations.kt included a migration to increase the time value with the specific offset time in millis
DBMigrationsTests.kt checks if the migration has been validated and the results are correct
ConfigureRoomPlugin.kt included schemas in android Test
AudioFileToComposition.kt gap is only added in between edited item excluded the last gap which was being added to the end
AudioTransformer.kt renamed the methods and transform audio return a file not a uri
AudioTransformerImpl.kt corrected the transformation logic and also included io exception if temp file failed to created
In cleanUp included cancel method
Using a new directory  inside the cache dir thus after saving if the file is in transformation directory then delete it mentioned the seekable audio types and transformer audio output type.
Removed the GainAudioProcessor.kt as this is already present in androidx.media3
Corrected Extension function in Transformer
Now in Ui layer add option to cancel the ongoing transformation, only a cancel button is added it will be later worked on
Made TransformationState.kt progress defer thus we only read the value when its drawn
Player shared
Removed ContentLoadState.kt functions OnContentOrOther and OnContent in each places when statement is used
Most of PlayerTrack data receivers are made lazy read
PlayerDurationText.kt corrected duration format and made track data read lazy and computed when changed via derived stateOf
PlayerTrackSlider2.kt uses SliderState api to provide a non recomposing slider, the track data with snapshot flow help to keep track of the positions
PlayerSliderController.kt moved to separate file
Keeping the old composable api for future
Now for player
AudioBookmarksList.kt kept the list state and the empty state inside the list only if the list is empty then the lazy column will hold the absent placeholder
As mentioned track data is now being lazy read at most parts
Moved AudioPlayerScreenContent.kt to separate file
Corrected clips in PlayerBookmarks.kt
In Editor
Removed surface and used box in AudioClipClipRow.kt
PlayerTrimSelector.kt modifiers DetectClipConfig.kt and EditorTrimOverlay.kt qualified name and inspector info mentioned and for pointerInput using Mutex so that no two operations overlaps and now these modifier are marked non-composable but uses compose modifier for composition scope
Included text for editor actions.
Some changes were also made to data layer will be corrected and commited later.
First PlayerMetaData.kt now doesn't provide playing info, the playing data can be received through AudioFilePlayer.isPlaying
In PlayerTrackDataFlow.kt also checking the timeline for any changes, thus when the media is loaded the timeline is prepared
Player other than isplaying info we may need buffering info too combining them PlayerPlayState.kt
PlayerIsPlayingFlow.kt provides flow for both isPlaying and PlayerPlayState.kt
As media controller is also a player following the same principle with AudioFilePlayer.kt the AudioFilePlayerImpl.kt controls the player and its controlled with MediaControllerProvider.kt
Included AudioMetadataRetriever.kt which maybe used in later future
IN EditableAudioPlayerImpl.kt a few corrections made here and there
MutexExt.kt provides a mutex extension to manage locks
As two of the players uses different exoplayer instance the config with audio attributes and media source factory is kept in PlayerCommonModule.kt
TaskExts.kt provides await function on Task object for location provider and
Included location enabled method
Included accuracy in BaseLocationModel.kt
CoarseLocationProviderImpl.kt returning correct exception for result for reading last location
LocationAddressProvider.kt now returns a result, in its implementation if geo coder is unable to decode location it returns an exception rather than a null,alongside removed the settings repo thus keeping single responsibility for the provider
MediaMetaDataInfo.kt made location string as nullable
 PlayerFileProviderImpl.kt using the settings repo to check if location string need to be fetched then using that string
PhoneStateObserverImpl.kt always emit a PhoneState.IDLE at starts
If bluetooth sco is absent beginScoConnection returns BluetoothSCONotAvailableException.kt
Included tests for ShareRecordingsUtil as bluetooth and phone state cannot be tested only attached share test, as content uri are required AndroidManifest.xml and test_file_paths.xml for android test are added
As we are applying test we need different datastore instances for test and actual thus DataStoreProvider.kt provides the DefaultDataStoreProvider.kt and TestDatastoreProvider.kt which are injected into repositories
TestDatastoreProvider.kt creates datastore instances via factory and files which are deleted at the end of each test
Moved the serializers into other file
VoiceRecorder.kt stop recording returns a result, in VoiceRecorderImpl.kt using locks extension, not querying location if the audio format doesn't allow option adding try finally block to ensure recorder is clear and pcm reader is reset
RecordFormats.kt is made into an enum class with specific recorder init helpers and RecordEncoderAndFormat.kt is removed
VoiceRecorderService.kt notification for recording time emit on each second using distinctUntilChanged
In AudioRecordAmplitudeReader.kt corrected the buffer size if stereo mode is enabled, moved rms function inside the class
RecordedPointExt.kt now using sequences rather than list to reduce creation of intermediate lists in between operations
Corrected Aliases.kt,
RecorderFileProvider.kt provides a result if file transfer from temp to shared storage is done, if transfer failed for any reason the file is deleted
In most cases MediaMetaDataInfo.kt is not required so it's wasteful to read these values as these required MediaExtractor
PlayerFileProvider.kt method include optional argument readMetadata to allow reading extra metadata
Using Result API rather in Resource in PlayerFileProvider.getAudioFileFromId
RecordingsContentResolverWrapper.kt in utils catching exceptions but only rethrowing if it's a securityexception
TrashRecordingsProvider.kt included both flow and resource based methods for deleting
RemoveTrashRecordingTaskImpl.kt the difference time is reduced to min 1 hr
Use of supervisorScope while creating and restoring trash recording files in TrashRecordingsProviderApi29Impl.kt
For trashing or deleting first the owner recording are moved then the non owner recordings emits the security exceptions which is handled in the Viewmodel
each of the handleSecurityException methods in viewmodel added a flag to enable it, only rename is made enabled
In Request handlers rememberUpdatedState used to get current lambda value
Using a handler thread ensures the media extraction is not made in the main thread thus reducing the pressure of the main thread
Included atomic and volatile fields to ensure values can be updated from multiple threads,
The callback in the class is changed to a listener.
FloatArrayExt.kt using array functions
Correction in ByteBufferExt.kt with 16 pcm encoding
In PlayerIsPlayingFlow.kt we need to filter the buffering state then check for playing or not playing
As graph data is lazy read inside canvas the only thing that's constantly changing in the screen is the timer text making the timer text lazy reduced recomposition count by a lot
RecorderServiceBinderImpl.kt using MutableStateflow rather than null using flow operators giving it a observable Service class
In AudioRecordAmplitudeReader.kt in audio read ensure the current coroutine context is active
For cancellation added a basic message
Splash screen icon may not be ready when animation is prepared so its causing a null point exception if icon cannot be found then go with basic view animation otherwise both
IN OnBoardingActivity.kt move setTransition in onCreate and keep on condition if boarding state is content
In RecorderApp.kt included Composer diagnostic stack trace option
Removed unwanted test cases from app module
Moved testing runtime dependency to custom android lib plugin
Some of the unwanted resources are removed and few translation were marked non-translatable
Updated the project dependencies to latest version
Updated the module graph
The workflow shows how many test has passed
Nothing new was added so it's a patch fix
Need to include android runner dependency for app:connectedAndroidTest to run
Mentioned to increate the heap size and meta size
Included other .idea files
BookMarksToCsvConvertorTest.kt @AfterTest method should return Unit corrected that
Updated the action version in android_build_ci.yaml
For publish test results permission checks write permission is needed
@github-actions
Copy link

github-actions bot commented Nov 2, 2025

Instrumented Test Results (API 36)

24 tests   24 ✅  10s ⏱️
24 suites   0 💤
24 files     0 ❌

Results for commit 3c9fe1b.

@tuuhin tuuhin merged commit f6896c7 into main Nov 2, 2025
3 checks passed
@tuuhin tuuhin deleted the enhancements branch November 2, 2025 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants